私は気づきました(私はかつてそれを言われ、同じこと(a -> a)
をa -> a
意味していましたが)、を使用するとエラーメッセージが表示されます(a -> a)
。(a -> a)
タイプの中でブラケットを使用する場合にのみ使用する必要がありますか?(つまり(5 + 3)
の代わりに5 + 3
)?いつ必要なのかよくわからない
5 に答える
(a -> a)
とは単独a -> a
で同じ,
ff :: (a -> a) -- this compiles
ff = id
gg :: a -> a
gg = id
h :: a -> a -> Bool
h _ _ = True
i = h ff gg -- this compiles => ff & gg are of the same type.
ただし、次のようなより多くのタイプと組み合わせると異なります。
a -> a -> b
(a -> a) -> b
これは->
が右結合であるため、a -> a -> b
実際にはa -> (a -> b)
(関数を取得して関数を返す) を意味し、(関数を取得して a を返すa
) とは異なります。(a -> a) -> b
b
これは と(1+2)*3
は違うようなものです1+2*3
。
コンパイラーが利用できる他の情報が役に立たない場合、括弧はHaskellのいくつかの構成を明確にします。
アプリケーションは左側に関連付けられています
したがって、関数の引数の親を省略できます。
中置演算子を含む式は、演算子の固定性によって明確になります。
したがって、多くの場合、固定度の異なる二項演算子を使用するパレンは必要ありません。
構文エラーを回避するために、同じ優先順位を持つ連続する括弧なしの演算子は、左または右の両方に関連付けられている必要があります。
そして最後に:
括弧で囲まれていない式の場合、優先順位に関する特定の条件が成立しない限り、またはの
x op y op z
前後に括弧を追加する必要があります。x op y
y op z
上記のステートメントが意味をなさない場合の私の一般的なアドバイス:ルールを学ぶまで、物事を括弧でくくりすぎてください。または、ハスケルレポートを一生懸命勉強してください。
式を考えてみましょう10 / 2 / 5
。それはまたはと同じ(10 / 2) / 5
ですか10 / (2 / 5)
?数学的除算であると解釈/
すると、前者は真であり、後者は偽です。ご覧のとおり、あなたの質問に対する答えは「違いはありますが、たまにしかありません」です。
タイプは逆です。a -> b -> c
は と同じですが、a -> (b -> c)
とはまったく同じではありません(a -> b) -> c
。
あなたは、それがいつ必要になるかよくわからないと言います。関数への引数も関数である場合は、それが必要です。
を考慮してくださいmap :: (a -> b) -> [a] -> [b]
。a -> b -> [a] -> [b]
ご覧のとおり、これは とは異なり(a -> b)
、特定の種類の関数、つまり type から typea
への関数を示しますb
。
iterate :: (a -> a) -> a -> [a]
はもっと面白いです。この関数では、最初のパラメーターの関数の入力と出力の型が同じである必要があります。
カリー化と部分適用について読むことに興味があるかもしれません。多くのリソースの 1 つ: Learn you a Haskell # Curried Functions
これは、高階関数を作成している場合にのみ違いがあります。例えば:
f :: a -> a -> b
type の 2 つの引数を期待し、 type の値を返す関数ですa
。b
f 2 2
f True True
しかし、機能
f :: (a -> a) -> b
引数として関数が必要です。ここのように、型推論の唯一の引数である場合にa -> a
とが同じになる唯一の時間(a -> a)
f :: (a -> a)
-- Same type as
f :: a -> a
入力の規則は()
、通常の式の場合とほとんど同じです。ワンランク上の表現のようなものです。
それらは同じです。を使用したときに発生するエラーについて説明していただけます(a -> a)
か? ghci-7.0.3 で問題なく動作します。
Prelude> let f :: (a -> a); f = id
Prelude> f "foo"
"foo"
Prelude>
一般に、関数を引数として使用する場合は、型に括弧を使用する必要があります。たとえば、map :: (a -> b) -> [a] -> [b]
. 括弧がなければ、別の意味になります。