2009-07-21 20 views
9

私は非常に簡単な質問があります。私はバインド演算子を使用するコードのブロックの後にwhere句を使用したいと思いますが、コンパイルエラーが発生します。ここでHaskell:バインド演算子(>> =)を持つブロックの後にwhere句を使用できますか?

は簡単な例です:

main = 
    putStrLn "where clause test:" >> 
    return [1..10] >>= \list -> 
    print list' 
     where list' = reverse list -- test1.hs:5:28: Not in scope: `list' 

私は

main = 
    putStrLn "where clause test:" >> 
    return [1..10] >>= \list -> 
    let list' = reverse list -- works of course 
    in print list' 

のように」リストについては、let節を使用することができますが、私は、where句を使用することができれば、私は本当にそれをしたいと思います。 ..私はまたしてみました

は表記

main = do 
    putStrLn "where clause test:" 
    list <- return [1..10] 
    print list' 
     where list' = reverse list --test3.hs:5:30: Not in scope: `list' 
行います

同じ問題があります。このような状況でwhere句を使用できますか?

答えて

10

エフェクティブに説明されているように、where句を使用することはできません。

エラーは、このコードで起こる:

main = 
    return [1..10] >>= \list -> 
    print list' 
    where 
     list' = reverse list 

where -clauseはメイン関数に取り付けられています。 listのバインディングがmain表現の奥深くではなく、何かwhere節ができます:私はあなたが「out of scope」エラーが出る理由そのはかなり明白だと思う

main = return [1..10] >>= (\list -> print list') 
    where 
    list' = reverse list 

ここではより多くの括弧と同じ機能ですリーチ。

私はこのような状況で通常何をしているのですか(そして私は同じことによって何度も噛まれました)。私は単純に関数を導入し、listを引数として渡します。もちろん

main = do 
    list <- return [1..10] 
    let list' = f list 
    print list' 
    where 
    f list = reverse list -- Consider renaming list, 
          -- or writing in point-free style 

は、私がf機能であなたの実際のコードは、多くのことだけreverseで想像し、あなたがwhere句の内部でそれをしたい理由は、代わりに結合インラインletで、です。 f関数内のコードが非常に小さい場合、私はちょうどletバインディング内にそれを記述し、新しい関数を導入するオーバーヘッドを逃しません。

+0

ありがとう、あなたの例では、より多くの括弧を使って私のためにそれをクリアします。 –

1

私が知る限り、where句はローカルバインディングでのみ使用されています。 >>(=)バインディング文の内部は、ローカルバインディング(その文の2種類のバインディング)ではありません。

このと比較する:

main = f [1..10] 

f list = 
    putStrLn "where clause test:" >> print list' 
     where list' = reverse list 

あなたはHaskell 98 syntax reportを参照したい場合があります - それはどのくらいの助けがわかりません。

私が間違っていると、確かに誰かが私を訂正しますが、あなたが上に示したようなスタイルでwhere節を使うことはできません。 listは、関数のパラメータでない限り、where句のスコープ内には存在しません。

+0

ラムダ抽象化は、新しい名前をバインドすることはできますが、宣言またはバインディングではなく、式です。 – ephemient

+0

Whoa、who'ed this?私はそれが正しいと思います。 – ephemient

+0

とは関係ありません。 OPは、モナド計算の束の真ん中からの結果である "リスト"を使用したい。モナド外の値ではない – newacct

11

問題がletことである - whereのみに使用することができるがinは、他の式の内部で使用することができる式であり、(モジュール|クラス|インスタンス| GADT | ...)宣言または(関数|パターン)結合。

declarations and bindings上ハスケル98レポート、

p | g1=e1
    | g2=e2
    …
    | gm=em
  where {decls}

p= letdeclsin
      ifg1thene1else
      ifg2thene2else
      …
      ifgmthenemelse error "Unmatched pattern"

や、ガードを除去することによって、物事を単純化するための糖であるから、

p=ewhere {decls}

のための糖である 機能とパターンの両方のバインディングで138

edo {&hellipの場合でも同様です。 }構築物。

あなたは大きな表現内の特定の部分式への結合ローカルを持っているしたい場合は、let使用する必要があります - in( - indo内部または単にletを、それがletのためだけの砂糖です)。"}電子where {decls" – whereは宣言のみとバインディングで使用することができる法的な表現ではありませんので、

あなたも

main = do 
    putStrLn "where clause test: " 
    list <- return [1..10] 
    (print list' where list' = reverse list) 

を書き込むことはできません。

main = do 
    putStrLn "where clause test: " 
    list <- return [1..10] 
    let list' = list'' where list'' = reverse list 
    print list' 

これは合法です(多少の工夫があれば)。

+0

「let list '= reverse list」だけではないのはなぜですか?最後の例では? – newacct

+0

ありがとう、私はこのような言語に関する根本的な質問がある場合、より頻繁にHaskellレポートを参照する必要があります。 –

+0

@newacct:OPの質問には既にその変種が含まれていますが、これは明らかに機能します。 – ephemient

関連する問題