25

HaskellmapM_のブロック内で関数呼び出しをリファクタリングしようとしています。doコードを読みやすくするために、ラムダを(ローカルで)名前の付いた関数に抽出したいと思います。

私のコードは元々次のようになっています:

do
  -- ...
  mapM_ (\x -> x + 1) aList

  return aValue

に変更したい

do
  -- ...
  mapM_ func aList
    where func x = x + 1

  return aValue

しかし、その行で構文エラーが発生していますreturn aValue。私の実際のラムダはもっと複雑です:-)、しかし私はそれがラムダコードの問題ではないことを確認するためにこれと同じラムダでそれを試しました。

このコードを書き直すにはどうすればよいですか?代わりにlet...を使用する必要がありますか?in

4

3 に答える 3

35

ここで物事を定義する3つの類似した(しかし異なる)方法があります:

  • 特定の定義の後に句を付加できwhereます。ほとんどの場合、方程式スタイルのバインディングです。letしたがって、関数の最後、または周囲のwhere句で定義されたものの後に1つ置くことができます。

  • 一方、let x = ... in ...は、後の部分に評価されるinであり、後の部分が表示される唯一の場所letです。

  • ブロック内には、スコープの暗黙的なネストがすでに存在するため(最初に定義された後に表示されます)、単独でdo使用できます。let x = ...これは実際には前のフォームと同じです。do後のブロックの残りの部分letは事実上そのin ...部分です。

ブロック内で定義されたものを使用するローカル定義が必要な場合do、唯一の選択肢は3番目です(または他の値を引数として渡します)。ただし、例のような独立したヘルパー関数の場合は、どのスタイルでも機能します。それぞれを示すための例を次に示します。

最初のスタイル。ここでは、句で定義されている他のものを含め、のfuncどこにでも表示されます。foowhere

foo = do ...
         mapM_ func aList
         ...
         return aValue
  where func x = x + 1

2番目のスタイル。ここでfuncは、式の内部にのみ表示されます。この場合は、ブロックlet全体です。do

foo = let func x = x + 1 
      in do 
         ...
         mapM_ func aList
         ...
         return aValue

そして3番目のスタイルは、doブロック内でそれを定義します。この場合、は;funcの後にのみ表示されます。let最初...はまだ定義されていません。

foo = do ...
         let func x = x + 1
         mapM_ func aList
         ...
         return aValue

ああ、そして良い意味で:let ... in ...は式なので、式がある場所ならどこでも使用して、いくつかのローカル定義に名前を付けることができます。したがって、別の例を次に示します。

foo = do ...
         let func x = x + 1 in mapM_ func aList
         ...
         return aValue

前と同じようにfunc、式の内部にのみ表示されletます。この場合は、その後の単一の式であり、他の場所には表示されません。

于 2012-12-30T17:44:59.730 に答える
10

もう1つのオプションは、引数の順序を逆にするのforM_代わりに使用することです。次に、次のような末尾のラムダ式で演算子をmapM_使用できます。$

do
  forM_ aList $ \x -> do
    ...

  return aValue
于 2012-12-30T17:50:02.713 に答える
3

あなたwhereは関数の終わりにいるべきではありませんか?

このような:

function aList aValue = do
    mapM_ func aList
    return aValue
    where func x = x + 1
于 2012-12-30T17:33:08.130 に答える