Haskellのいとも奇妙なる演算子

Haskell は他の言語では見慣れない演算子が多々あって戸惑う。特に気になった主要なものをまとめる。

文脈で意味が異なる演算子・記法

 |  (1) ガード条件
(2) リスト内包表記の区切り (such that) (例) [func x | x<-[1..9]]
(3) 列挙型の定義で列挙の区切り
 <-  (1) アクションから値を取り出す
(2) リスト内包表現のジェネレータ (例) [func x | x<-[1..9]]
 ->  (1) 関数の型定義 (例) inc :: Int -> Int
(2) ラムダ式定義 (例) inc = \x -> x + 1
(3) case式

モナドにまつわる演算子・関数

<- モナドから値を取り出す ※1
return 値を入れてモナドを作る ※2
>>= モナドから値を取り出して、モナドを返す関数に渡す。→方向。bind ※3
=<< モナドから値を取り出して、モナドを返す関数に渡す。←方向。bind ※3
<$> モナドから値を取り出して、ふつうの関数(※4)に渡し、戻り値をモナドに入れる。
fmap、ファンクター ※5
<*> モナドから値を取り出して、モナドに入った関数に渡す。戻り値はモナドに入る。
ap、アプリカティブファンクター ※5
>> モナドからの値を捨てて、次に移る。
>=> モナドを返す関数を合成する。→方向。
<=< モナドを返す関数を合成する。←方向。

※1:doブロックの中で使う。doブロックは最後にはアクションを返す。
※2:関数から抜けるわけでもないので注意。
※3:アクションを返さない関数には渡せない。
※4:引数も戻り値もモナドでない関数
※5:2個以上の引数を取るふつうの関数にモナドを渡す場合、1個目の引数は<$>を、2個目以降の引数は<*>を使って渡す。

見慣れない演算子・記法

$ 関数適用演算子。右結合なので関数の引数の閉じカッコを省略できる
`関数` 関数を中置演算子化する (例) 5 `mod` 2
(演算子) 中置演算子を関数化する (例) (+) 1 2
!! リストから要素を取り出す (例) [1,2,3,4,5] !! 2
++ リストの結合
: リストの先頭に要素を挿入 ※1
\ ラムダ式。円記号ではなくバックスラッシュ。(例) inc = \x -> x + 1
:: 型指定
. 関数の合成
<|> 左が Nothing なら右を評価
() 値が無いことを表し、unit と呼ぶ
_ 文法規則ではないが、未使用の変数は _ で表す習慣
' この文字を変数名や関数名に使える言語は珍しい。(例) x'

※1:末尾には挿入できないので ++ を使用して結合する。

C言語等と異なる書き方をする演算子・関数

div 整数の商 (関数)
mod 整数の剰余 (関数)
/= 非等価(ノットイコール)。C言語の !=
not 論理否定。C言語の ! ※1
.&. ビット演算 AND ※2
.|. ビット演算 OR ※2
complement ビット演算 NOT ※2
xor ビット演算 XOR ※2
^ 整数型のべき乗
** 浮動小数点型のべき乗

※1:論理積論理和C言語と同じく &&, || である。
※2:Data.Bitsの import が必要。

その他、注意を要する記法

-- 1行コメント
{- -} 複数行コメント
, 関数の引数はコンマで区切らずに並べる
リスト [ ] やタプル ( ) の要素はコンマで区切って並べる
( ) 関数の引数が複数あるとき、括弧で括らない
do 手続き的に実行する
where ローカル変数を後に定義する。
数学の決まり文句のwhere (日本語では「ここで」)
let ローカル変数を使う前に定義する。do とセットで、あるいは in の前に
if then else 値を返すので、C言語三項演算子のように使える
otherwise ガードでその他の場合
case of 関数の中でパターンマッチする。= でなく ->を使う