ここがすごいよ Hsakell の $ 演算子

最近ちょろっと Haskell を書いてて 『$ 演算子すげー』ってなったので勢いでまとめてみる。
Haskell に明るくないのでゆるふわな感じで書いていくよー。
(ちなみに $ 自体の具体的な解説はしない。

関数適用と演算子の優先順位

他言語をやってから Haskell を学び始めると次のようなコードを書いてしまうことが多いと思う。

main = do
    -- 1 + 2 の結果を出力したいなっ
    print 1 + 2

しかし、上記のコードでは次のようなエラーになってしまう。

test.hs:3:16:
    No instance for (Num (IO ())) arising from a use of ‘+’
    In the expression: print 1 + 2
    In an equation for ‘main’: main = print 1 + 2

これは Haskell では『演算子よりも関数適用の優先順位が高い』ためである。
どういうことかというと括弧がない場合、 Haskell では以下のように解釈してしまうからである。

(print 1) + 2

つまり

  • 1 + 2 の結果を print に渡す

のではなくて

  • print 1 の結果を + 2 する

という処理になる。
こういう場合は括弧を使用して処理の優先順位を明示化して回避する必要がある。

main = do
    -- 先に 1 + 2 を処理するよ!
    print (1 + 2)

括弧の代わりに $ を使う

さて、括弧を使うことで回避することは出来た。
しかし、『いちいち括弧を書きたくない!!』というのが人の性でである。
そういう場合によく利用されているのが $ 演算子である。
この $ 演算子を使うことで次のようにして括弧を記述することなく適切に処理を行う事が出来る。

main = do
    -- 1 + 2 が先に処理されるよ!
    print $ 1 + 2

やったね!!これで括弧を書かなくてよくなったよ!!

$ 演算子の仕組みを解説

と、いうだけだと物足りないのでもう少し $ 演算子の仕組みについて解説。
先ほど『関数適用よ演算子よりも関数適用の優先順位が高い』とかいた。
なので

f 20 + f 10

みたいな処理は

(f 20) + (f 10)

のように『f 関数を先に適用してから』 + 演算子が呼び出されることになる。
これを別の視点から考えてみると演算子の『左辺』と『右辺』を先に処理するという風に解釈する事が出来る。
同様に + 演算子を $` 演算子に置き換えて考えてみると

f $ g 10

(f) $ (g 10)

のように処理される。
つまり $ 演算子を使うことで『左辺と右辺を別々に処理する』という事ができるようになるのである。
これにより $ 演算子で括弧を使わなくても処理の優先順位を制御することが出来ることになる。
ちなみに $ 演算子演算子の中で優先順位が低いので

print $ 1 + 2

(print $ (1 + 2))

となる。

まとめ

  • $ 演算子は処理の優先順位を制御できる
    • これにより括弧の記述を省略する事が出来る
  • Haskell において演算子よりも関数適用のほうが優先順位が高い
    • f a + g h(f a) + (g h) となる
  • 式が複雑になってくるなら素直に括弧を書こう

あと $ が具体的にどういう関数なのかはあえてここではかかないけど、気になったら調べてみてね!!