「48時間でSchemeを書こう」の版間の差分

削除された内容 追加された内容
→‎戻り値: 一部訳出
347 行
</syntaxhighlight>
 
このようなプログラミングスタイル、つまり関数合成、関数適用、関数を引数にとる関数の多用は、Haskellコードで非常によく見られます。この手法によって、途中のステップを色んな方法で組み合わせることのできる他の関数に分解し、非常に複雑なアルゴリズムを一行で表現できることがよくあります。残念ながら、これはしばしばHaskellコードを型に注意しながら右から左に読まなければいけなくなることも意味します。このチュートリアルの残りでもっと沢山の例を見ていくことになるので、あなたは大分これに慣れることが出来るでしょう。
This style of programming - relying heavily on function composition, function application, and passing functions to functions - is very common in Haskell code. It often lets you express very complicated algorithms in a single line, breaking down intermediate steps into other functions that can be combined in various ways. Unfortunately, it means that you often have to read Haskell code from right-to-left and keep careful track of the types. We'll be seeing many more examples throughout the rest of the tutorial, so hopefully you'll get pretty comfortable with it.
 
文字列、数字、アトムの何れかを受け付けるパーサを作りましょう。
Let's create a parser that accepts either a string, a number, or an atom:
 
<syntaxhighlight lang="haskell">
parseExpr :: Parser LispVal
parseExpr =:: parseAtomParser LispVal
parseExpr = parseAtom
&lt;|&gt; parseString
&lt;<|&gt;> parseNumberparseString
<|> parseNumber
</syntaxhighlight>
 
そしてそれが<code>readExpr</code>が呼ばれるようにします。
And edit readExpr so it calls our new parser:
 
<syntaxhighlight lang="haskell">
readExpr :: String -&gt;> String
readExpr input = case parse <span style="color:red">parseExpr</span> "lisp" input of
Left err -&gt; "No match: " ++ show err
Left Right _err -&gt;> "FoundNo match: value" ++ show err
Right _ -> "Found value"
</syntaxhighlight>
 
このコードをコンパイル・実行すると、このプログラムがどんな数、文字列、記号でも受理するけれども、他のものは受け付けないことがわかるでしょう。
Compile and run this code, and you'll notice that it accepts any number, string, or symbol, but not other strings:
 
<syntaxhighlight lang="text">
debian:/home/jdtang/haskell_tutorial/code# ghc -package parsec -o simple_parser [.../code/listing3.3.hs listing3.3.hs]
% ghc -package parsec -o simple_parser simple-parser.hs
debian:/home/jdtang/haskell_tutorial/code#% ./simple_parser "\"this is a string\""
Found value
debian:/home/jdtang/haskell_tutorial/code# ./simple_parser 25
% ./simple_parser 25
Found value
debian:/home/jdtang/haskell_tutorial/code# ./simple_parser symbol
% ./simple_parser symbol
Found value
debian:/home/jdtang/haskell_tutorial/code# ./simple_parser (symbol)
% ./simple_parser (symbol)
bash: syntax error near unexpected token `symbol'
debian:/home/jdtang/haskell_tutorial/code#% ./simple_parser "(symbol)"
No match: "lisp" (line 1, column 1):
unexpected "("
expecting letter, "\"" or digit
</syntaxhighlight>
 
練習問題
# 以下の手法を使って<code>parseNumber</code>を書き直しなさい。
# Rewrite parseNumber using
## do-notation記法
## explicit sequencing with the [http://www.haskell.org/onlinereport/standard-prelude.html#tMonad &gt;&gt;>>=] operator演算子を使った明示的なシーケンシング
# ここでの文字列リテラルは、文字列中の引用符のエスケープをサポートしていないので、完全に[http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_sec_6.3.5 R5RS compliant]ではありません。<code>\"</code>が文字列を終わりにせず、二重引用符のリテラル表現となるように<code>parseString</code>を変えなさい。<code>noneOf "\""</code>を非引用符''又は''バックスラッシュと引用符を受理する新しいパーサアクションに置き換えるとよいでしょう。
# Our strings aren't quite [http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_sec_6.3.5 R5RS compliant], because they don't support escaping of internal quotes within the string. Change parseString so that \" gives a literal quote character instead of terminating the string. You may want to replace <code>noneOf "\""</code> with a new parser action that accepts ''either'' a non-quote character ''or'' a backslash followed by a quote mark.
# <code>\n</code>、<code>\r</code>、<code>\t</code>、<code>\\</code>などのエスケープ文字も認識するようにしなさい。
# Modify the previous exercise to support \n, \r, \t, \\, and any other desired escape characters
# Change <code>parseNumber to support the </code>が[http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_sec_6.2.4 Scheme standard for different bases]. You may find the もサポートするようにしなさい。それにあたっては[http://www.haskell.org/onlinereport/numeric.html#sect14 readOct and readHex] functions useful.が便利でしょう。
# Add a <code>Character constructor to </code>コンストラクタを<code>LispVal, and create a parser for </code>に加え、R5RSに書かれているように[http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_sec_6.3.4 character literals] as described in R5RS.のパーサを実装しなさい。
# Add a <code>Float constructor to </code>コンストラクタを<code>LispVal, and support R5RS syntax for </code>に加え、[http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_sec_6.2.4 decimals]. The Haskell function のR5RSにおける文法をサポートしなさい。[http://www.haskell.org/onlinereport/numeric.html#sect14 readFloat] may be useful.を使うとよいでしょう。
# Add data types and parsers to support the Schemeの数値型の[http://www.schemers.org/Documents/Standards/R5RS/HTML/r5rs-Z-H-9.html#%_sec_6.2.1 full numeric tower] of Scheme numeric types. を実装するデータ型とパーサを書きなさい。Haskell has built-in types to represent many of these; check the はこれらの多くを表現する組み込みの型を持っています。[http://www.haskell.org/onlinereport/standard-prelude.html#$tNum Prelude]. For the others, you can define compound types that represent eg. a Rational as a numerator and denominator, or a Complex as a real and imaginary part (each itself a Real number).を参照して下さい。Haskellに標準でない型については、複合型を定義できます。例えば、有理数は分母と分子の組で、複素数は実数部と虚数部の組で表すことができます。
 
=== Recursive Parsers: Adding lists, dotted lists, and quoted datums ===