Syntaxe de la clause Haskell where dans un bloc do
J'essaie de refactoriser un appel de fonction mapM_
dans un bloc do
dans Haskell. Je voudrais extraire le lambda dans une fonction nommée (localement) pour rendre le code plus lisible.
Mon code ressemble à l'origine à ceci:
do
-- ...
mapM_ (x -> x + 1) aList
return aValue
Je voudrais le changer pour
do
-- ...
mapM_ func aList
where func x = x + 1
return aValue
Mais je reçois une erreur de syntaxe sur la ligne return aValue
. Mon lambda réel est plus compliqué : -), mais je l'ai essayé avec ce même lambda pour m'assurer que ce n'était pas un problème dans le code lambda.
Comment puis-je réécrire ce code? Dois-je utiliser let
... in
à la place?
3 réponses
Il y a trois façons similaires (mais distinctes) de définir les choses ici:
Vous pouvez joindre des clauses
where
après certaines définitions-principalement des liaisons de type équation. Vous pouvez donc en mettre un à la fin de votre fonction, ou après quelque chose défini aveclet
ou une clausewhere
environnante.D'autre part,
let x = ... in ...
est un expression, ce qui correspond à la partie aprèsin
, qui est le seul endroit où les choses aprèslet
est visible.Dans un bloc
do
, car il y a déjà une imbrication implicite de la portée (les choses sont visibles après leur première définition), vous pouvez utiliser seulementlet x = ...
seul. C'est vraiment la même chose que la forme précédente-le reste du blocdo
après lelet
est effectivement la partiein ...
.
Si vous voulez une définition locale qui utilise quelque chose défini dans le bloc do
, votre seul choix est le troisième (ou en passant l'autre (s) valeur (s) comme argument (S)). Pour une fonction d'aide indépendante comme votre exemple, cependant, tout style fonctionne. Voici votre exemple, pour démontrer chacun:
Le premier style, où {[16] } est visible n'importe où dans foo
, y compris tout ce qui est défini dans la clause where
:
foo = do ...
mapM_ func aList
...
return aValue
where func x = x + 1
Le deuxième style, où func
n'est visible qu'à l'intérieur de l'expression let
, qui dans ce cas est le bloc do
entier:
foo = let func x = x + 1
in do
...
mapM_ func aList
...
return aValue
Et le troisième style, le définissant à l'intérieur du bloc do
. Dans ce cas, {[16] } n'est visible qu'après le let
; dans le premier ...
, Il n'a pas encore été défini.
foo = do ...
let func x = x + 1
mapM_ func aList
...
return aValue
Oh, et pour faire bonne mesure: puisque let ... in ...
est une expression, vous pouvez également l'utiliser partout où vous avez une expression, pour nommer certaines définitions locales. Voici donc un autre exemple:
foo = do ...
let func x = x + 1 in mapM_ func aList
...
return aValue
Comme précédemment, {[16] } n'est visible qu'à l'intérieur de l'expression let
, qui dans ce cas est l'expression unique après elle, nulle part ailleurs.
Une autre option consiste à utiliser forM_
au lieu de mapM_
, qui retourne l'ordre des arguments. Vous pouvez ensuite utiliser l'opérateur $
avec une expression lambda finale comme ceci:
do
forM_ aList $ \x -> do
...
return aValue
Votre where
ne devrait-il pas être à la fin de la fonction?
Comme ceci:
function aList aValue = do
mapM_ func aList
return aValue
where func x = x + 1