2012-12-30 14 views
19

mapM_関数呼び出しをHaskellのdoブロック内でリファクタリングしようとしています。私はラムダを(ローカルに)名前付き関数にコードを読みやすくするために抽出したいと思います。私のコードは本来、このようになりますハスケルwhere節の構文doブロック内

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

    return aValue 

私は

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

    return aValue 

にそれを変更したいと思いますが、私はreturn aValueラインの構文エラーを取得しています。私の実際のラムダはより複雑です:-)、しかし、ラムダコードで問題ではないことを確認するために、この同じラムダで試しました。

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

答えて

27

ここのものを定義する3類似した(しかし、明確な)方法があります: - ほとんどの方程式スタイルのバインディング

  • は、あなたが特定の定義後where句を添付することができ、このよう

    。だから、関数の最後に、またはletまたはそれに囲まれたwhere節で定義されたものを置くことができます。一方

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

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

あなたはdoブロック内で定義されたものを使用してローカル定義をしたい場合は、あなたの唯一の選択肢は、第三(または引数(複数可)として他の値(複数可)を渡して)です。しかし、あなたの例のような独立したヘルパー関数の場合、どんなスタイルでも動作します。ここではあなたの例だ、それぞれを発揮します

funcが他where句で定義されたものを含め、どこにでもfooに表示されている最初のスタイル、:

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

秒スタイル、funcは内部のみ表示されます

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

そして第三に、スタイル、定義:この場合には全体doブロックでlet表現、それはdoブロック内にあります。この場合、funcletの後にのみ表示されます。最初の...ではまだ定義されていません。

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表現、内部にのみ表示されます。

+0

ありがとうございます。 3番目の形式は、 'mapM_'に十分近づいてラムダ関数を定義できるようになります。私は、 'let'(マイナーな問題)で定義された' func'という名前でトップレベルの関数名前空間を汚染することだけを心配しています。 – Ralph

+0

@Ralph:これは、どのようなスコープを表示したいのかという問題です。 'do'ブロックが十分大きければ、内部の名前空間を汚染することを心配する必要があります。とにかく、 。 :] –

+0

ええ、それも私に起こっていた。私はいくつかの馬鹿が書いた機能的なScalaコード(:-))を、それよりも長い関数で翻訳しています。 – Ralph

3

あなたのwhereは機能の最後にあるべきではありませんか?

function aList aValue = do 
    mapM_ func aList 
    return aValue 
    where func x = x + 1 
+0

わかりません。ラムダを読みやすくするために非常に局所的な関数に抽出する方法を探したいと思います。トップレベルの関数の最後に置かなければならない場合、それはずっと使いにくいものになります。私はハスケルのノブです。 – Ralph

10

もう1つの方法は、mapM_の代わりにforM_を使用して、引数の順序を反転させることです。 演算子を次のような末尾のラムダ式で使用できます。

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

    return aValue 
+0

私はその代替案を考えていませんでした。私は再び読むことができるかどうかを確認するために私のコードを見ていきます。私がモナディックリストトラバーサルを必要とする他のケースでは、 'forM_'のような便利なフリップバージョンは存在しません。新しい関数を作るのに' flip 'を使うことができます。 – Ralph