10

とても簡単な質問があります。bind 演算子を使用するコード ブロックの後に where 句を使用したいのですが、コンパイル エラーが発生します。

簡単な例を次に示します。

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

次のように、list' に let 句を使用できます。

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

しかし、where句を使用できれば本当にいいのですが...

私もdo表記で試しました

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 句を使用できますか?

4

3 に答える 3

11

ephemientが説明してwhereいるように、句を自分のように使用することはできません。

このコードでは、次の理由でエラーが発生します。

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

-clausewhereはmain関数に付加されます。

括弧を増やした同じ関数を次に示します。

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

「」エラーが発生する理由はかなり明白だと思いout of scopeます。のバインディングlistは式の奥深くにあり、句が到達できるmainものではありません。where

私がこの状況で通常行うこと(そして私は同じことを何度も噛まれてきました)。関数を導入し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、句内にコードを配置する必要があります。関数内のコードが非常に小さい場合は、バインディング内にコードを記述するだけで、新しい関数を導入するオーバーヘッドは発生しません。whereletflet

于 2009-07-21T06:02:46.973 に答える
11

問題は、let-inが式であり、他の式の内部で使用whereできる一方で、(module | class | instance | GADT | ...)宣言または(function | pattern)バインディングでのみ使用できることです。

宣言とバインディングに関するHaskell98レポートから、

p | g 1 = e 1
    | g 2e2     …     | = _ _ g m e m decls

=
  where { }

砂糖です

p = let decls in
      if g 1 then e 1 else
      if g 2e2       … gme mthen _ _ _ _else

      if then else error "Unmatched pattern"

または、ガードを削除して物事を簡素化し、

p = e where { decls }

砂糖です

p = let decls in e

関数バインディングとパターンバインディングの両方で。これは、edo {}構成である場合でも当てはまります。

より大きな式内の特定の部分式にローカルなバインディングが必要な場合は、let-を使用する必要がありますin(または単に。let内にありますが、これは-doの単なる砂糖です)。letin

書くことすらできない

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

edecls 」は where { 正当 }な表現ではないwhereため、宣言とバインディングでのみ使用できます。

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

これは合法です(多少工夫されている場合)。

于 2009-07-21T04:15:49.810 に答える
1

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

これと比較してください:

main = f [1..10]

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

Haskell 98 構文レポートを参照することをお勧めします- それがどれほど役立つかはわかりません。

私が間違っていれば、誰かが間違いなく訂正してくれるでしょうが、上で示したスタイルでは where 句をまったく使用できないと確信しています。 list関数のパラメーターでない限り、where 句のスコープにはなりません。

于 2009-07-21T03:26:55.417 に答える