Haskell impur

Le problème exposé dans ce sujet a été résolu.

Bonjour,

Il y a longtemps j’avais essayé d’apprendre à coder en Haskell. J’avais bloqué sur les monades pour diverses raisons. Mais ça ne m’a pas empêché de continuer à coder en Haskell.

Sauf qu’aujourd’hui, je suis confronté à un problème simple mais que je ne sais pas résoudre.

J’ai une fonction qui prend un paramètre et le transforme. Je voudrais que si on l’appel 2 fois avec le même argument, elle retourne deux choses différentes.

En gros, je veux un truc impur.

1
2
3
4
>nbCall "1"
"1_0"
>nbCall "1"
"1_1"

Il y a t’il une solution ?

Merci d’avance 😃

+0 -0

Je ne suis pas vraiment convaincu que ça soit une bonne idée, mais tu peux utiliser le package Data.IORef. Exemple:

1
2
3
4
5
6
7
8
> import Data.Functor
> import Data.IORef
> cnt <- newIORef 0
> let add p = modifyIORef cnt (+1) >> (+p) <$> readIORef cnt
> add 0
1
> add 10
12

Salut,

Tu peux utiliser la monade State pour faire ça:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
import Control.Monad.State

type NbCall a = State Int a

runNbCall :: NbCall a -> a
runNbCall st = evalState st 0

nbCall :: String -> NbCall String
nbCall s = gets (\ n -> s ++ "_" ++ show n) <* modify (+1)

fn :: NbCall String
fn = nbCall "1" >> nbCall "1"

main :: IO ()
main = print (evalNbCall fn)

Si tu veux avoir d’autres effets en plus, tu peux combiner ta monade avec d’autres en utilisant le monad transformer StateT:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
import Control.Monad.State

type NbCall m a = StateT Int m a

runNbCall :: Monad m => NbCall m a -> m a
runNbCall st = evalStateT st 0

nbCall :: Monad m => String -> NbCall m String
nbCall s = gets (\ n -> s ++ "_" ++ show n) <* modify (+1)

-- Fonction pouvant effectuer à la fois des actions de type `NbCall` et `IO` (via `lift`)
fn :: NbCall IO ()
fn = do
  lift . print =<< nbCall "1"  -- Appelle `nbCall` et affiche le résultat
  lift . print =<< nbCall "1"

main :: IO ()
main = runNbCall fn

dab: Je pense pas que ça soit une super idée non plus, ça va forcer le PO à travailler dans la monade IO qui est overkill pour faire simplement ça. De plus, en utilisant une monad transformer, on peut combiner les effets ce qu’on aurait pas pu faire avec IO (on en aurait pas eu besoin mais autant restreindre les effets de bord le plus possible).

Edit: Erreurs de ma part, j’avais pas testé mon code, ça m’apprendra

+1 -0

@ache : quel serait le prototype attendu de nbCall. Tu ne peux pas le faire avec une fonction pure (i.e. nbCall :: String -> String), par contre tu vas avoir plein de monades ad hoc qui vont te permettre un comportement comme tu l’évoques (cf. les réponses de mes voisins du dessus).

+0 -0

Merci de vos réponses.
Étant donné ma difficulté à comprendre les monades, je vais m’attarder un peu sur vos exemples pour bien comprendre.

@lthms: C’est pour un filtre Pandoc. Par la fonction toJSONFilter. Du coup, normalement, je devrais pouvoir me débrouiller si j’étudie la chose correctement.

Merci beaucoup pour vos réponses. J’étudie calmement ça à tête reposée … 🍹

+0 -0

Rien de secret victor ^^
Je suis ravi d’y répondre, même si c’est un chouilla HS.

Une sorte de zMarkdown mais pour des exercices de Maths.

Du style :

1
2
3
>secret
>
>

Pour créer un QCM

1
2
3
> + qcm
> + = Bonnne réponse
> + !  Mauvaise

Bref, ce serra distribué sous GNU GPL si le résultat est satisfaisant. C’est à destination de profs de Maths/Physique, pour faciliter la création d’exercices à correction automatique sur les ENT.

Si tu as d’autres questions, j’y répondrais par MP.

+3 -0

[…] par contre tu vas avoir plein de monades ad hoc qui vont te permettre un comportement comme tu l’évoques

lthms

Oui mais il n’y a que State qui ne fait, ni plus, ni moins, ce que ache demande. IO est une monade fourre tout donc évidemment tout effet de bord peut avoir lieu au sein de celle-ci. L’un des buts des monades étant de restreindre les effets à des contextes précis, à mon avis il vaut mieux opter pour la solution minimale, à savoir State, quitte à combiner plusieurs effets avec les monad transformers si besoin.

Là où @felko a raison, c’est qu’une telle monade va très certainement utiliser une monade état sous le capot, même si caché par un newtype par exemple. Je suis tout à fait d’accord pour dire que State est la bonne méthode ici.

+0 -0
Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte