Haskellの字句構造・キーワード

(2017.1) 大幅加筆, Haskell 2010対応。

Haskellは, 字下げによってブロック (ソースコードの意味上のかたまり) を表すものがあります。また、新しい演算子をユーザが定義でき、さらに優先順位も指定できるという、変態な機能があります。

Haskell コンパイラすごい。

このページでは、厳密さは追求せず、簡単に Haskell の字句構造について書きます。

表記

ソースコードは UTF-8 で書きます。識別子、演算子の文字として, Unicode文字が使えます。

{ pattern } 0回以上の繰り返し
( pattern ) グルーピング
pat1 | pat2どちらか
pat<pat'>patで生成される文字列, ただしpat'以外

コメント

コメントは空白に置き換えられます。

--」から行末までか,「{-」から「-}」までの間です。

-- のほうは、演算子の一部であるときはコメントになりません。例えば, -->|-- では、コメントは始まりません。

{--} はネスト可能。

ソースコード冒頭では、コンパイラ pragma としても使います。

{-# LANGUAGE TypeFamilies               #-}
{-# LANGUAGE TemplateHaskell            #-}
{-# LANGUAGE GADTs                      #-}
{-# LANGUAGE MultiParamTypeClasses      #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}

module Model where

import Database.Persist.TH
...以下略

識別子・キーワード

識別子 (identifier) は大文字・小文字を区別する。小文字始まりが variable identifier, 大文字始まりが constructor identifier.

varid
→ (small {small | large | digit | ' })<予約語>
conid
large {small | large | digit | ' }

Haskellの予約語はこれだけ。少ない。"_" も予約語.

case class data default deriving do else foreign if import in infix infixl infixr instance let module newtype of then type where _

if式

TODO: 構文を解説するページに移動。

Haskell の if は, 文ではなく式。Haskell にはナル値がなく、何かしら値を返すため, else 節が必須. then節とelse節の式の型が同じでなければならない。加えて, 構文解析の都合上, then キーワードも省略できない。

lexp
\ apat1 ... apatn -> exp
| let decls in exp
| if exp [;] then exp [;] else exp
| case exp of { alts }
| do { stmts }
| fexp

このような if式は,

if e1 then e2 else e3    

次のように書き換えられる (等価);

case e1 of { True -> e2 ; False -> e3 }

演算子

Haskell は、幅広い文字列をユーザ定義演算子にできるので, 構文上予約された演算子は非常に少ない。

varsym
→ ( symbol<:> { symbol } )<reservedop | dashes>
consym
→ ( : { symbol } )<reservedop>
reservedop
.. | : | :: | = | \ | "|" | <- | -> | @ | ~ | =>

>>= ですら, 構文上は予約された演算子ではない。

演算子として使える文字は次のとおり. Unicode 文字が使える。

symbol
ascSymbol | uniSymbol<special | _ | " | ' >
ascSymbol
→ ! | # | $ | % | & | * | + | . | / | < | = | > | ? | @ | \ | ^ | "|" | - | ~ | :
uniSymbol
→ any Unicode "Symbol" or "Punctuation"
special
→ "(" | ")" | , | ; | [ | ] | ` | "{" | "}"

字句構造はともかく、標準ライブラリで定義された演算子は次の通り;

優先順位左結合 非結合 右結合
9 !! .
8 ^ ^^ **
7 * / `div` `mod` `rem` `quot`
6 + -
5 : ++
4 == /= < <= > >= `elem` `notElem`
3 &&
2 ||
1 >> >>=
0 $ $! `seq`

Symbol や Punctuation が具体的にどんな文字かは, ここで見れます; Unicode Character Categories Unicode の General_Category 値.

リテラル

整数, 実数

別ページ Haskellの基本データ型

文字, 文字列

単一文字は 'あ', 文字列は "あいう".

標準では文字列リテラルは String型になる。ただ、Stringは効率がよくなく、新しいプログラムでは使わない。現代では, OverloadedStrings プラグマを使うことで、文字列リテラルの型を Text または ByteString にする。厳密には, IsString型クラスのインスタンスの型。

Unicodeコードポイントを\xに続けて16進で, 10ffffまでの値を書ける。6桁ではなくて、本当にこの値を超えるとエラーになる。字句解析すごい。

リスト, タプル

●書く。

レイアウト (Layout)

レイアウト (またはoff-side) ルール。 where, let, do および of. この4つのキーワードについて、オフサイドルールが適用される。

●例を書く.