7

私はそれに頭を包み始めました。むしろ、1つの出力から1つの入力に値を本質的にパイプできる単純な状況で使用するのが好きです。私が満足している無意味な構成の簡単な例は次のとおりです。

let joinLines = foldr (++) "" . intersperse "\n"

今日 GHCI で遊んでいるときに、 を構成not(==)て複製できるかどうかを確認したかったの(/=)ですが、実際にはそれを推論できませんでした。(==)2 つの入力をnot取り、1 つを取ります。私はこれがうまくいくかもしれないと思った:

let ne = not . (==)

Boolの単一の出力が(==)に移動すると仮定するとnot、次のエラーを引用してコンパイルされません。

<interactive>:1:16:
    Couldn't match expected type `Bool' with actual type `a0 -> Bool'
    Expected type: a0 -> Bool
      Actual type: a0 -> a0 -> Bool
    In the second argument of `(.)', namely `(==)'
    In the expression: not . (==)

それが私にとって大きな意味があると言えたらいいのにと思いますが、私が得ているのは、渡された2番目の引数(==)not? この構成の背後にあるロジックをもう少しよく理解するのを手伝ってくれる人はいますか?

4

3 に答える 3

15

一度に 1 つの引数を削除し始めると、次のようになります。

ne x y = not (x == y)
       = (not . (x ==)) y
ne x   = not . (x ==)
       = not . ((==) x)
       = ((not .) . (==)) x
ne     = (not .) . (==)

(.)基本的に、すべての引数に対して、適切に関連付けられたが必要です。

の型は(==)ですEq a => a -> a -> Bool。したがって、 を書きwhatever . (==)、それに値xを渡すと、 が得られますがwhatever ((==) x)、これ(==) xは関数ですa -> Bool(aは の型でxあり、 のインスタンスですEq)。したがって、whatever関数型の引数を受け入れる必要があります。

于 2012-09-13T15:22:04.923 に答える
13

もう1つの便利な演算子は(。:)です。これは、2つの引数を取る初期関数のコンビネータです。

f . g  $ x
f .: g $ x y
于 2012-09-13T19:45:32.713 に答える