違いは何ですか 。(ドット) と $ (ドル記号)?
-
06-09-2019 - |
質問
ドットの違いは何ですか (.)
そしてドル記号 ($)
?
私の理解では、どちらも括弧を使用する必要がないための糖衣構文です。
解決
の $
演算子は括弧を避けるためのものです。その後に表示されるものは、前に表示されるものよりも優先されます。
たとえば、次のような行があるとします。
putStrLn (show (1 + 1))
これらの括弧を削除したい場合は、次のいずれかの行でも同じことができます。
putStrLn (show $ 1 + 1)
putStrLn $ show (1 + 1)
putStrLn $ show $ 1 + 1
の主な目的は、 .
演算子は括弧を避けるためではなく、関数を連鎖させるためのものです。これにより、右側に表示されるものの出力を左側に表示されるものの入力に結び付けることができます。これにより通常は括弧の数も減りますが、動作は異なります。
同じ例に戻ります。
putStrLn (show (1 + 1))
(1 + 1)
入力がないため、.
オペレーター。show
取ることができますInt
そして、を返しますString
.putStrLn
取ることができますString
そして、IO ()
.
連鎖することができます show
に putStrLn
このような:
(putStrLn . show) (1 + 1)
括弧が多すぎる場合は、次のコマンドを使用して括弧を削除してください。 $
オペレーター:
putStrLn . show $ 1 + 1
他のヒント
彼らは、異なるタイプと異なる定義があります:
infixr 9 .
(.) :: (b -> c) -> (a -> b) -> (a -> c)
(f . g) x = f (g x)
infixr 0 $
($) :: (a -> b) -> a -> b
f $ x = f x
($)
は、正常な機能のアプリケーションを置き換えることを意図されているが、異なる優先で括弧を避けるために。 (.)
は、新しい関数を作るために一緒に二つの機能を構成するためである。
いくつかのケースでは、彼らは交換可能ですが、これは一般的には真実ではありません。彼らは典型的な例があります:
f $ g $ h $ x
==>
f . g . h $ x
$
sの鎖における言い換えれば、最終的な一つを除く全てが.
に置き換えることができる
また、種類ののを機能に特化している($)
であるのアイデンティティ機能に注意してください。恒等関数は次のようになります:
id :: a -> a
id x = x
($)
は次のように見えますが。
($) :: (a -> b) -> (a -> b)
($) = id
私は意図的に型シグネチャに余分な括弧を追加したことに注意してください。
($)
の用途は、通常、(オペレータがセクションで使用されていない限り)括弧を追加することによって除去することができます。例えば:f $ g x
がf (g x)
になります。
(.)
の使用は、多くの場合、交換する少し困難です。彼らは通常、ラムダまたは明示的な関数パラメータの導入を必要とします。たとえばます:
f = g . h
となります。
f x = (g . h) x
となります。
f x = g (h x)
この情報がお役に立てば幸い!
($)
は、関数は、評価順序を制御するために括弧を追加せずに一緒に連鎖することを可能にする
Prelude> head (tail "asdf")
's'
Prelude> head $ tail "asdf"
's'
コンオペレータ(.)
は、引数を指定せずに新しい関数を作成します:
Prelude> let second x = head $ tail x
Prelude> second "asdf"
's'
Prelude> let second = head . tail
Prelude> second "asdf"
's'
上記の例では、間違いなく、例示であるが、実際に組成物を使用しての利便性を示しません。ここでは別の類推だ。
Prelude> let third x = head $ tail $ tail x
Prelude> map third ["asdf", "qwer", "1234"]
"de3"
私たちは一度だけ三分の一を使用している場合は、私たちはラムダを使用することによって、それを付けないようにすることができます:
Prelude> map (\x -> head $ tail $ tail x) ["asdf", "qwer", "1234"]
"de3"
最後に、組成物は、私たちは、ラムダを避けることができます:
Prelude> map (head . tail . tail) ["asdf", "qwer", "1234"]
"de3"
短くて優しいバージョン:
($)
は、右側の引数である値に対して左側の引数である関数を呼び出します。(.)
左側の引数である関数を、右側の引数である関数上に合成します。
一つの応用であなたのHaskellの
を学ぶ:以来ます:f $ x = f x
と中置演算子を含む式の右辺は、プレフィックス関数に変換し、一方は($ 3) (4+)
に類似(++", world") "hello"
を書き込むことができる括弧で囲む。
なぜ誰もがこれを行うのでしょうか?関数のリストについては、例えば。どちらます:
map (++", world") ["hello","goodbye"]`
と
map ($ 3) [(4+),(3*)]
map (\x -> x ++ ", world") ...
またはmap (\f -> f 3) ...
よりも短くなっています。もちろん、後者の変異体は、ほとんどの人にとって読みやすくなります。
...またはあなたが使用して.
と$
構造を避けることができ、のパイプラインの
third xs = xs |> tail |> tail |> head
それはあなたがヘルパー関数に追加した後です。
(|>) x y = y x
何についての詳細を学ぶのに最適な方法を(任意の関数)、すべてが関数であることを覚えておくことです!その一般的なマントラは役立ちますが、事業者のような特定のケースでは、この小さなトリックを覚えておくのに役立ちます:
:t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
と
:t ($)
($) :: (a -> b) -> a -> b
ただ、自由:t
を使用し、()
であなたの演算子をラップすることを忘れないでください!
私のルールは簡単です(私も初心者です)。
- 使ってはいけません
.
パラメータを渡したい(関数を呼び出す)場合、そして - 使ってはいけません
$
パラメータがまだない場合(関数を作成する)
あれは
show $ head [1, 2]
しかし決して:
show . head [1, 2]
ハスケル:との差
.
(ドット)と$
(ドル記号)ドットの違いは何ですか
(.)
そしてドル記号($)
?。私の理解では、どちらも括弧を使用する必要がないための糖衣構文です。
彼らです ない 括弧を使用する必要がないための糖衣構文 - これらは関数であり、中置されているため、演算子と呼ぶことができます。
作曲、 (.)
, 、いつ使用するか。
(.)
作成機能です。それで
result = (f . g) x
に渡された引数の結果を渡す関数を構築するのと同じです。 g
に向かって f
.
h = \x -> f (g x)
result = h x
使用 (.)
作成したい関数に渡すための引数がない場合。
右連想が適用され、 ($)
, 、いつ使用するか
($)
は、バインドの優先順位が低い右結合適用関数です。したがって、最初にその右側にあるものを計算するだけです。したがって、
result = f $ g x
手続き的にはこれと同じです (Haskell は遅延評価されるため、これは重要です。Haskell は評価を開始します) f
初め):
h = f
g_x = g x
result = h g_x
またはもっと簡潔に言うと:
result = f (g x)
使用 ($)
前述の関数を結果に適用する前に、評価する変数がすべて揃っている場合。
これは、各関数のソースを読むことでわかります。
ソースを読む
こちらが ソース のために (.)
:
-- | Function composition.
{-# INLINE (.) #-}
-- Make sure it has TWO args only on the left, so that it inlines
-- when applied to two functions, even if there is no final argument
(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g = \x -> f (g x)
そして、これが ソース のために ($)
:
-- | Application operator. This operator is redundant, since ordinary
-- application @(f x)@ means the same as @(f '$' x)@. However, '$' has
-- low, right-associative binding precedence, so it sometimes allows
-- parentheses to be omitted; for example:
--
-- > f $ g $ h x = f (g (h x))
--
-- It is also useful in higher-order situations, such as @'map' ('$' 0) xs@,
-- or @'Data.List.zipWith' ('$') fs xs@.
{-# INLINE ($) #-}
($) :: (a -> b) -> a -> b
f $ x = f x
結論
関数をすぐに評価する必要がない場合は、合成を使用します。合成の結果として得られた関数を別の関数に渡したい場合があります。
完全な評価のためにすべての引数を指定する場合は、 application を使用します。
したがって、この例では、意味的に次のようにすることが望ましいでしょう。
f $ g x
私たちが持っているとき x
(というより、 g
の引数)、次のようにします。
f . g
そうしないとき。
私はあなたが物事を明確に役立つだろう.
$
を使用していないでしょうどこの短い例だと思います。
double x = x * 2
triple x = x * 3
times6 = double . triple
:i times6
times6 :: Num c => c -> c
times6
関数組成物から作成された関数であることに注意してください。
他のすべての答えはかなり良いです。しかし、どのようにGHC扱い$についての重要なユーザビリティの詳細はGHC型チェッカーは、上位/定量化タイプとinstatiarionを可能にすること、があります。あなたが例えば$ id
の種類を見れば、あなたはそれがその引数自体が多型の機能である機能を取るつもりだ見つけることができます。そのようなささいなことは、同等の動揺オペレータと同じ柔軟性を与えられていません。 (これは実際には$!が同じ治療に値するかないなら、私は思ってしまう)。