この章では,Haskell の下位レベルの字句構造について説明する. このレポートを初めて読む場合には,詳細のほとんどは飛ばしてかまわない.
次にあげる表記規約は構文を表現するために用いる.
[pattern] | オプション |
{pattern} | 0回またはそれ以上の繰り返し |
(pattern) | グループ化 |
pat1 | pat2 | 選択 |
pat⟨pat′⟩ | 差— pat で生成された要素から |
pat′ で生成されたものを除いたもの |
|
fibonacci | 終端構文はタイプライタフォント |
この節で構文といえば 字句構文のことなので,すべての白空白は明示的に表現する. 隣接するシンボルの間には暗黙の空白は存在しない. 次のような生成ルールをもつ BNF 風の構文を用いる.
nonterm | → | alt1 | alt2 | … | altn |
| および […] のようなメタロジック構文と(タイプライタフォントで与えられた)| および [...] のような具象終端構文を区別するようにしなければならない. しかし,これらの区別は通常文脈から明らかなものである.
Haskell では Unicode [2] 文字集合を使う.しかしながら,ソースプログラムは現時点では早い段階の版で専ら使用されていた ASCII 文字集合に偏ったものである.
この構文は Unicode コンソーシアムが定義した Unicode 文字の性質に依存する. Haskell コンパイラは利用可能な Unicode の新しいバージョンを使うことが推奨されている.
program | → | { lexeme | whitespace } |
lexeme | → | qvarid | qconid | qvarsym | qconsym |
| | literal | special | reservedop | reservedid | |
literal | → | integer | float | char | string |
special | → | ( | ) | , | ; | [ | ] | ` | { | } |
whitespace | → | whitestuff {whitestuff} |
whitestuff | → | whitechar | comment | ncomment |
whitechar | → | newline | vertab | space | tab | uniWhite |
newline | → | return linefeed | return | linefeed | formfeed |
return | → | キャリッジリターン |
linefeed | → | ラインフィード |
vertab | → | 垂直タブ |
formfeed | → | フォームフィード |
space | → | 空白 |
tab | → | 水平タブ |
uniWhite | → | 白空白として定義されている任意の Unicode 文字 |
comment | → | dashes [ any⟨symbol⟩ {any} ] newline |
dashes | → | -- {-} |
opencom | → | {- |
closecom | → | -} |
ncomment | → | opencom ANY seq {ncomment ANY seq} closecom |
ANY seq | → | {ANY }⟨{ANY } ( opencom | closecom ) {ANY }⟩ |
ANY | → | graphic | whitechar |
any | → | graphic | space | tab |
graphic | → | small | large | symbol | digit | special | " | ' |
small | → | ascSmall | uniSmall | _ |
ascSmall | → | a | b | … | z |
uniSmall | → | 任意の Unicode 小文字 |
large | → | ascLarge | uniLarge |
ascLarge | → | A | B | … | Z |
uniLarge | → | 任意の Unicode 大文字あるい任意の Unicode 語頭文字 |
symbol | → | ascSymbol | uniSymbol⟨special | _ | " | '⟩ |
ascSymbol | → | ! | # | $ | % | & | ⋆ | + | . | / | < | = | > | ? | @ |
| | \ | ^ | | | - | ~ | : | |
uniSymbol | → | 任意の Unicode シンボルあるいは Unicode 句読点 |
digit | → | ascDigit | uniDigit |
ascDigit | → | 0 | 1 | … | 9 |
uniDigit | → | 任意の Unicode 十進数字 |
octit | → | 0 | 1 | … | 7 |
hexit | → | digit | A | … | F | a | … | f |
字句解析では「最長一致」規則を使うべきで,それぞれの位置で 字句生成規則を満す最長の字句が読み込まれる.したがって,caseは予約語であるが,casesは予約語ではない. 同様に,= は予約されているが, == および ~= は予約されていない.
あらゆる種類の白空白は字句を区切る適切な区切り子である.
ANY の範疇に入らない文字はHaskellでは使用できない. 使用すれば字句解析エラーにならなければならない.
通常のコメントは2つ以上連続したダッシュ(たとえば,--)で構成される字句で始まり次の改行までである.(コメント開始の)ダッシュの並びは正しい字句の一部にしては決してならない. たとえば,「-->」あるいは「|--」はコメントの開始にはならない.そのわけは,両方ともに正しい字句だからである. 一方,「--foo」はコメントの開始になる.
ネストしたコメントは「{-」という字句で開始し,「-}」で終了する.正しい字句で「{-」から始まるものはない. したがって,たとえば, 「{---」は余分なダッシュが付いてはいるがネストしたコメントの開始となる.
コメントそのものは字句解析の対象にはならない. その代わりに最初の未対応「-}」によって対応するネストしたコメントは終了する. ネストしたコメントは何段にもネストすることが可能で,「{-」があらわれるたびに新しいネストしたコメントが開始され,それらは,それぞれ対応する「-}」で終了する.
(ネストコメントではない)通常のコメント内では,文字列「{-」および「-}」は特別な意味を持たない. また,ネストコメント内ではダッシュの並びには特別な意味はない.
ネストコメントはコンパイラに対するプラグマとしても用いられる. これについては12で説明する.
コードをネストコメントでコメントアウトした場合には,コメントアウトしたコード中の文字列(リテラル)内にある {- あるいは -} の出現に影響を受ける. また,コメントアウトされたコード中の行コメント内の{- あるいは -} の出現にも影響を受ける.
varid | → | (small {small | large | digit | ' })⟨reservedid⟩ |
conid | → | large {small | large | digit | ' } |
reservedid | → | case | class | data | default | deriving | do | else |
| | foreign | if | import | in | infix | infixl | |
| | infixr | instance | let | module | newtype | of | |
| | then | type | where | _ |
識別子は英字ではじまり,英字,数字,アンダースコア,シングルクウォートが 0 個ないしそれ以上つづく. 識別子は字句としては 2 つの名前空間(1.4節)に分けられ区別される. 小文字で始まる識別子(変数識別子)と,大文字で始まる識別子(構成子識別子)である. 識別子では,大文字,小文字は区別される. name, naMe,Nameはそれぞれ別の識別子である(最初の 2 つは変数識別子,最後のものは構成子識別子である).
アンダースコア「_」は小文字と見なされ,小文字が出現可能な場所で使用できる. しかしながら,「_」それ自身は予約済の識別子であり,パターンにおいてワイルドカードとして使用する. 未使用の識別子に対して警告を出すコンパイラではアンダースコアで始まる識別子に対する警告は抑制することを推奨されている. それ故、プログラマは不使用 を期待されているような「_foo」をパラメータとして使用することも可能である.
varsym | → | ( symbol⟨:⟩ {symbol} )⟨reservedop | dashes⟩ |
consym | → | ( : {symbol})⟨reservedop⟩ |
reservedop | → | .. | : | :: | = | \ | | | <- | -> | @ | ~ | => |
演算子シンボル は 1 つ以上のシンボル文字で上記のように構成される.また,字句としては 2 つの名前空間(1.4節)に分けられ区別される.
コロンそのもの「:」は,Haskell のリスト構成子専用に予約されていることに注意すること. この扱いは,他にリスト構文,「[]」や「[a,b]などと同じである.
前置符号反転演算子の特別な構文除けば,すべての演算子は中置である. しかしながら,中置演算子は セクションで部分適用演算子として使用できる(3.5 節参照). 標準の中置演算子はすべてあらかじめ定義済のシンボルである. また,再定義可能である.
varid | (変数) | ||
conid | (構成子) | ||
tyvar | → | varid | (型変数) |
tycon | → | conid | (型構成子) |
tycls | → | conid | (型クラス) |
modid | → | {conid .} conid | (モジュール) |
変数と型変数は小文字で始まる識別子で表現され,それ以外の 4 つは大文字で始まる識別子で表現される. また,変数と構成子は中置形式をもち,それ以外の 4 つは中置形式はもたない. モジュール名は複数の conid をドットで区切って並べたものである. 名前空間については 1.4 節で議論する.
状況によっては,名前の前にモジュール名を置いて修飾することもある. この修飾子の付加は変数,構成子,型構成子,型クラスに対して行われるもので,型変数,モジュール名に対しては行われない. 修飾された名前についての詳細な議論は 5章で行う.
qvarid | → | [modid .] varid |
qconid | → | [modid .] conid |
qtycon | → | [modid .] tycon |
qtycls | → | [modid .] tycls |
qvarsym | → | [modid .] varsym |
qconsym | → | [modid .] consym |
修飾された名前は全体で 1 つの字句なので,修飾子と名前の間に空白を置くことはできない. 字句解析は単純に以下に示すように行われる.
これは | このように字句解析される |
f.g | f . g (3 つのトークン) |
F.g | F.g(修飾された ‘g’) |
f.. | f ..(2 つのトークン) |
F.. | F..(修飾された ‘.’) |
F. | F .(2 つのトークン) |
decimal | → | digit{digit} |
octal | → | octit{octit} |
hexadecimal | → | hexit{hexit} |
integer | → | decimal |
| | 0o octal | 0O octal | |
| | 0x hexadecimal | 0X hexadecimal | |
float | → | decimal . decimal [exponent] |
| | decimal exponent | |
exponent | → | (e | E) [+ | -] decimal |
There are two distinct kinds of numeric literals: integer and floating. Integer literals may be given in decimal (the default), octal (prefixed by 0o or 0O) or hexadecimal notation (prefixed by 0x or 0X). Floating literals are always decimal. A floating literal must contain digits both before and after the decimal point; this ensures that a decimal point cannot be mistaken for another use of the dot character. Negative numeric literals are discussed in Section 3.4. The typing of numeric literals is discussed in Section 6.4.1.
char | → | ' (graphic⟨' | \⟩ | space | escape⟨\&⟩) ' |
string | → | " {graphic⟨" | \⟩ | space | escape | gap} " |
escape | → | \ ( charesc | ascii | decimal | o octal | x hexadecimal ) |
charesc | → | a | b | f | n | r | t | v | \ | " | ' | & |
ascii | → | ^cntrl | NUL | SOH | STX | ETX | EOT | ENQ | ACK |
| | BEL | BS | HT | LF | VT | FF | CR | SO | SI | DLE | |
| | DC1 | DC2 | DC3 | DC4 | NAK | SYN | ETB | CAN | |
| | EM | SUB | ESC | FS | GS | RS | US | SP | DEL | |
cntrl | → | ascLarge | @ | [ | \ | ] | ^ | _ |
gap | → | \ whitechar {whitechar} \ |
Character literals are written between single quotes, as in 'a', and strings between double quotes, as in "Hello".
Escape codes may be used in characters and strings to represent special characters. Note that a single quote ' may be used in a string, but must be escaped in a character; similarly, a double quote " may be used in a character, but must be escaped in a string. \ must always be escaped. The category charesc also includes portable representations for the characters 「alert」 (\a), 「backspace」 (\b), 「form feed」 (\f), 「new line」 (\n), 「carriage return」 (\r), 「horizontal tab」 (\t), and 「vertical tab」 (\v).
Escape characters for the Unicode character set, including control characters such as \^X, are also provided. Numeric escapes such as \137 are used to designate the character with decimal representation 137; octal (e.g. \o137) and hexadecimal (e.g. \x37) representations are also allowed.
Consistent with the 「maximal munch」 rule, numeric escape characters in strings consist of all consecutive digits and may be of arbitrary length. Similarly, the one ambiguous ASCII escape code, "\SOH", is parsed as a string of length 1. The escape character \& is provided as a 「null character」 to allow strings such as "\137\&9" および "\SO\&H" to be constructed (both of length two). Thus "\&" is equivalent to "" and the character '\&' is disallowed. Further equivalences of characters are defined in Section 6.1.2.
A string may include a 「gap」—two backslants enclosing white characters—which is ignored. This allows one to write long strings on more than one line by writing a backslant at the end of one line and at the start of the next. For example,
String literals are actually abbreviations for lists of characters (see Section 3.7).
Haskell permits the omission of the braces and semicolons used in several grammar productions, by using layout to convey the same information. This allows both layout-sensitive and layout-insensitive styles of coding, which can be freely mixed within one program. Because layout is not required, Haskell programs can be straightforwardly produced by other programs.
The effect of layout on the meaning of a Haskell program can be completely specified by adding braces and semicolons in places determined by the layout. The meaning of this augmented program is now layout insensitive.
Informally stated, the braces and semicolons are inserted as follows. The layout (or 「off-side」) rule takes effect whenever the open brace is omitted after the keyword where, let, do, or of. When this happens, the indentation of the next lexeme (whether or not on a new line) is remembered and the omitted open brace is inserted (the whitespace preceding the lexeme may include comments). For each subsequent line, if it contains only whitespace or is indented more, then the previous item is continued (nothing is inserted); if it is indented the same amount, then a new item begins (a semicolon is inserted); and if it is indented less, then the layout list ends (a close brace is inserted). If the indentation of the non-brace lexeme immediately following a where, let, do or of is less than or equal to the current indentation level, then instead of starting a layout, an empty list 「{}」 is inserted, and layout processing occurs for the current level (i.e. insert a semicolon or close brace). A close brace is also inserted whenever the syntactic category containing the layout list ends; that is, if an illegal lexeme is encountered at a point where a close brace would be legal, a close brace is inserted. The layout rule matches only those open braces that it has inserted; an explicit open brace must be matched by an explicit close brace. Within these explicit open braces, no layout processing is performed for constructs outside the braces, even if a line is indented to the left of an earlier implicit open brace.
Section 10.3 gives a more precise definition of the layout rules.
Given these rules, a single newline may actually terminate several layout lists. Also, these rules permit:
making a, b および g all part of the same layout list.
As an example, Figure 2.1 shows a (somewhat contrived) module and Figure 2.2 shows the result of applying the layout rule to it. Note in particular: (a) the line beginning }};pop, where the termination of the previous line invokes three applications of the layout rule, corresponding to the depth (3) of the nested where clauses, (b) the close braces in the where clause nested within the tuple and case expression, inserted because the end of the tuple was detected, and (c) the close brace at the very end, inserted because of the column 0 indentation of the end-of-file token.