Haskell impur

L'auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

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 😃

ache.one                                                            🦊

+0 -0

Cette réponse a aidé l'auteur du sujet

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
+0 -0

Cette réponse a aidé l'auteur du sujet

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

Édité par felko

Anciennement AlphaZeta

+2 -0

Cette réponse a aidé l'auteur du sujet

@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
Auteur du sujet

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 … 🍹

ache.one                                                            🦊

+0 -0

Eh ache, pas obligé de répondre parce que c’est très accessoire vu ta question MAIS tu fiches quoi avec Pandoc, par curiosité ?

Le saviez-vous ? Chaque -1 que vous mettez vous fait gagner un point de QI.

+0 -0
Auteur du sujet

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.

ache.one                                                            🦊

+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.

Anciennement AlphaZeta

+3 -0

@felko : On pourrait imaginer une monade qui ne permet pas de modifier arbitrairement le compteur, seulement de l’incrémenter (garantie de ne pas retourner en arrière en utilisant du code externe).

+1 -0

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
Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

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