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?

21
demandé sur Ralph 2012-12-30 21:20:40

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 avec let ou une clause where environnante.

  • D'autre part, let x = ... in ... est un expression, ce qui correspond à la partie après in, qui est le seul endroit où les choses après let 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 seulement let x = ... seul. C'est vraiment la même chose que la forme précédente-le reste du bloc do après le let est effectivement la partie in ....

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.

29
répondu C. A. McCann 2012-12-30 17:44:59

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
10
répondu hammar 2012-12-30 17:50:02

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
3
répondu antoyo 2012-12-30 17:33:08