Difference between revisions of "10分で学ぶHaskell"

From HaskellWiki
Jump to navigation Jump to search
(→‎構造化されたデータ: 訳の修正とコードの整形)
(17 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
== 概要 ==
 
== 概要 ==
   
  +
Haskellは関数型で(つまりすべてが関数呼びだしで処理される)、静的な暗黙的型付けで([[型]]はコンパイラによって確認され、明示的に宣言する必要はない)、遅延評価(必要となるまで処理されない)の言語です。系統が近い言語として最も人気のあるのはおそらくML系の言語でしょう。(MLは遅延評価ではないですが)
Haskell is a functional (that is, everything is done with function calls), statically, implicitly typed ([[type]]s are checked by the compiler, but you don't have to declare them), lazy (nothing is done until it needs to be) language. Its closest popular relative is probably the ML family of languages (which are not, however, lazy languages).
 
   
The most common Haskell compiler is [[GHC]]. You can download GHC from http://www.haskell.org/ghc/download.html . GHC binaries are available for [[GNU/Linux]], [[BSD | FreeBSD]], [[Mac OS X |MacOS]], [[Windows]], and [[Solaris]]. Once you've installed [[GHC]], you get two programs you're interested in right now: <tt>ghc</tt>, and <tt>[[GHC/GHCi | ghci]]</tt>. The first compiles Haskell libraries or applications to binary code. The second is an interpreter that lets you write Haskell code and get feedback right away.
+
最も普及しているHaskellのコンパイラは [[GHC]] です。GHC http://www.haskell.org/ghc/download.html からダウンロードできます。GHCのバイナリは [[GNU/Linux]][[BSD | FreeBSD]][[Mac OS X | MacOS]][[Windows]][[Solaris]]で動作します。[[GHC]]をインストールすると、<tt>ghc</tt><tt>[[GHC/GHCi | ghci]]</tt>という2つのプログラムが入っているのが確認できます。最初の<tt>ghc</tt>の方はHaskellのライブラリやアプリケーションをバイナリコードにコンパイルします。<tt>[[GHC/GHCi | ghci]]</tt>はインタプリタで、Haskellコードを書いてすぐに結果を得ることができる環境です。
   
== 簡表現 ==
+
== 簡数式 ==
   
  +
たいていの数式は直接<tt>ghci</tt>に入力して計算結果を得ることができます。<tt>Prelude></tt>はGHCiのデフォルトのプロンプトです。
You can type most math expressions directly into <tt>ghci</tt> and get an answer. <tt>Prelude></tt> is the default GHCi prompt.
 
   
  +
<tt>
Prelude> <hask>3 * 5</hask>
 
  +
:Prelude> <hask>3 * 5</hask>
15
 
  +
:15
Prelude> <hask>4 ^ 2 - 1</hask>
 
  +
:Prelude> <hask>4 ^ 2 - 1</hask>
15
 
  +
:15
Prelude> <hask>(1 - 5)^(3 * 2 - 4)</hask>
 
  +
:Prelude> <hask>(1 - 5)^(3 * 2 - 4)</hask>
16
 
  +
:16
  +
</tt>
   
  +
文字列はダブルクォート(二重引用符)で囲みます。文字列の結合をするときは<hask>++</hask>を使います。
Strings are in "double quotes." You can concatenate them with <hask>++</hask>.
 
   
  +
<tt>
Prelude> <hask>"Hello"</hask>
 
"Hello"
+
:Prelude> <hask>"Hello"</hask>
  +
:"Hello"
Prelude> <hask>"Hello" ++ ", Haskell"</hask>
 
"Hello, Haskell"
+
:Prelude> <hask>"Hello" ++ ", Haskell"</hask>
  +
:"Hello, Haskell"
  +
</tt>
   
  +
[[関数]]を呼び出すときは関数の後に直接引数を並べて行います。関数呼び出しに括弧は必要ありません。こんな感じです:
Calling [[function]]s is done by putting the arguments directly after the function. There are no parentheses as part of the function call:
 
   
  +
<tt>
Prelude> <hask>succ 5</hask>
 
  +
:Prelude> <hask>succ 5</hask>
6
 
  +
:6
Prelude> <hask>truncate 6.59</hask>
 
  +
:Prelude> <hask>truncate 6.59</hask>
6
 
  +
:6
Prelude> <hask>round 6.59</hask>
 
  +
:Prelude> <hask>round 6.59</hask>
7
 
  +
:7
Prelude> <hask>sqrt 2</hask>
 
  +
:Prelude> <hask>sqrt 2</hask>
1.4142135623730951
 
  +
:1.4142135623730951
Prelude> <hask>not (5 < 3)</hask>
 
  +
:Prelude> <hask>not (5 < 3)</hask>
True
 
  +
:True
Prelude> <hask>gcd 21 14</hask>
 
  +
:Prelude> <hask>gcd 21 14</hask>
7
 
  +
:7
  +
</tt>
   
 
== コンソール ==
 
== コンソール ==
   
  +
[[IO入門編|I/Oアクション]]はコンソールからの入出力を行うのに使います。よくある例は:
[[Introduction to IO |I/O actions]] can be used to read from and write to the console. Some common ones include:
 
   
  +
<tt>
Prelude> <hask>putStrLn "Hello, Haskell"</hask>
 
Hello, Haskell
+
:Prelude> <hask>putStrLn "Hello, Haskell"</hask>
  +
:Hello, Haskell
Prelude> <hask>putStr "No newline"</hask>
 
No newlinePrelude> <hask>print (5 + 4)</hask>
+
:Prelude> <hask>putStr "No newline"</hask>
  +
:No newlinePrelude> <hask>print (5 + 4)</hask>
9
 
  +
:9
Prelude> <hask>print (1 < 2)</hask>
 
  +
:Prelude> <hask>print (1 < 2)</hask>
True
 
  +
:True
  +
</tt>
   
The <hask>putStr</hask> and <hask>putStrLn</hask> functions output strings to the terminal. The <hask>print</hask> function outputs any type of value. (If you <hask>print</hask> a string, it will have quotes around it.)
+
<hask>putStr</hask>関数 <hask>putStrLn</hask>関数 は文字列をターミナルに出力します。<hask>print</hask>関数はどんな型の値でも出力します。(文字列を<hask>print</hask>するときは、引用符が前後につきます)
   
  +
ひとつの式の中で複数の I/O アクションを使いたい場合は、<hask>do</hask>ブロックを使います。アクションはセミコロンで区切られます。
If you need multiple I/O actions in one expression, you can use a <hask>do</hask> block. Actions are separated by semicolons.
 
   
  +
<tt>
Prelude> <hask>do { putStr "2 + 2 = " ; print (2 + 2) }</hask>
 
  +
:Prelude> <hask>do { putStr "2 + 2 = " ; print (2 + 2) }</hask>
2 + 2 = 4
 
  +
:2 + 2 = 4
Prelude> <hask>do { putStrLn "ABCDE" ; putStrLn "12345" }</hask>
 
  +
:Prelude> <hask>do { putStrLn "ABCDE" ; putStrLn "12345" }</hask>
ABCDE
 
  +
:ABCDE
12345
 
  +
:12345
  +
</tt>
   
Reading can be done with <hask>getLine</hask> (which gives back a <hask>String</hask>) or <hask>readLn</hask> (which gives back whatever type of value you want). The <hask> <- </hask> symbol is used to assign a name to the result of an I/O action.
+
読み込みは <hask>getLine</hask><hask>String</hask>を返します)か<hask>readLn</hask>(どんな型の値でも返します)でできます。<hask> <- </hask>という記号はI/Oアクションの結果に名前を付けるために使います。
   
  +
<tt>
Prelude> <hask>do { n <- readLn ; print (n^2) }</hask>
 
  +
:Prelude> <hask>do { n <- readLn ; print (n^2) }</hask>
4
 
  +
:4
16
 
  +
:16
  +
</tt>
   
  +
(4が入力で16が結果です。)
(The 4 was input. The 16 was a result.)
 
   
  +
別の書き方で<hask>do</hask>ブロックを書くこともできます。中括弧やセミコロンを使わずに、インデントでブロックと式の区切りを表します。<tt>ghci</tt>では書けないので、ソースファイル(例えば<tt>Test.hs</tt>)に書いてビルドしてみましょう。
There is actually another way to write <hask>do</hask> blocks. If you leave off the braces and semicolons, then indentation becomes significant. This doesn't work so well in <tt>ghci</tt>, but try putting the file in a source file (say, <tt>Test.hs</tt>) and build it.
 
   
 
<haskell>
 
<haskell>
Line 78: Line 90:
 
</haskell>
 
</haskell>
   
You can build with <tt>ghc --make Test.hs</tt>, and the result will be called <tt>Test</tt>. (On [[Windows]], <tt>Test.exe</tt>) You get an <hask>if</hask> expression as a bonus.
+
ビルドは <tt>ghc --make Test.hs</tt> でできます。実行ファイル <tt>Test</tt> ができるはずです。([[Windows]]では<tt>Test.exe</tt>となります)ここで<hask>if</hask>式も一緒に習得できてしまいますね。
   
  +
<hask>do</hask>の直後の最初の空白でない文字は特別な文字です。上の例の場合では<hask>putStrLn</hask>の先頭の<tt>p</tt>がそれです。<hask>do</hask>ブロック内のすべての行はその<hask>p</hask>と同じ列から開始します。もしインデントがより深ければ、それ以前の行の一部となります。逆にインデントが浅ければ、<hask>do</hask>ブロックはそこで終わります。これは“レイアウト”と呼ばれ、Haskellでは、いつも行の区切り文字や中括弧を使うのは面倒なので、代わりにレイアウトを使います。(<hask>then</hask>句と<hask>else</hask>句はこれが理由で<hask>if</hask>よりインデントが深くなければならないのです。もし<hask>if</hask>と同じ列から開始した場合、<hask>if</hask>と別の行と解釈されてしまって、エラーとなります。)
The first non-space character after <hask>do</hask> is special. In this case, it's the <tt>p</tt> from <hask>putStrLn</hask>. Every line that starts in the same column as that <hask>p</hask> is another statement in the <hask>do</hask> block. If you indent more, it's part of the previous statement. If you indent less, it ends the <hask>do</hask> block. This is called "layout", and Haskell uses it to avoid making you put in statement terminators and braces all the time. (The <hask>then</hask> and <hask>else</hask> phrases have to be indented for this reason: if they started in the same column, they'd be separate statements, which is wrong.)
 
   
  +
(Note: レイアウトを使う場合はインデントにタブを'''用いないでください'''。技術的にはタブが8文字であれば動作しますが、おすすめできません。また中には使う人もいるかもしれませんが、プロポーショナルフォントを使うこともおすすめしません。
(Note: Do '''not''' indent with tabs if you're using layout. It technically still works if your tabs are 8 spaces, but it's a bad idea. Also, don't use proportional fonts -- which apparently some people do, even when programming!)
 
   
== 簡な型 ==
+
== 簡な型 ==
   
  +
これまで、[[型]]宣言に関して全く触れてきませんでした。それはHaskellが型推論を行うからです。一般的に型宣言はしたい場合以外はする必要がありません。型宣言をする場合は<hask>::</hask>を使って行います。
So far, not a single [[type]] declaration has been mentioned. That's because Haskell does type inference. You generally don't have to declare types unless you want to. If you do want to declare types, you use <hask>::</hask> to do it.
 
   
  +
<tt>
Prelude> <hask>5 :: Int</hask>
 
  +
:Prelude> <hask>5 :: Int</hask>
5
 
  +
:5
Prelude> <hask>5 :: Double</hask>
 
  +
:Prelude> <hask>5 :: Double</hask>
5.0
 
  +
:5.0
  +
</tt>
   
  +
Haskellでは[[型]] (そして後で触れる型[[クラス]])は常に大文字から開始します。変数は常に小文字から始まります。これは言語仕様であり、命名規則([[Studly capitals|naming convention]])ではありません。
[[Type]]s (and type [[class]]es, discussed later) always start with upper-case letters in Haskell. Variables always start with lower-case letters. This is a rule of the language, not a [[Studly capitals|naming convention]].
 
   
  +
<tt>ghci</tt>を使って、ある値がどんな型かを確認することもできます。普段、自分では型宣言をしないので、この機能は役に立ちます。
You can also ask <tt>ghci</tt> what type it has chosen for something. This is useful because you don't generally have to declare your types.
 
   
 
Prelude> :t <hask>True</hask>
 
Prelude> :t <hask>True</hask>
Line 104: Line 118:
 
<hask>"Hello, Haskell" :: [Char]</hask>
 
<hask>"Hello, Haskell" :: [Char]</hask>
   
(In case you noticed, <hask>[Char]</hask> is another way of saying <hask>String</hask>. See the [[#Structured data|section on lists]] later.)
+
(上の例を見て気づいたように、<hask>[Char]</hask><hask>String</hask>の別名です。あとでを[[#Structured data|section on lists]]を見てみましょう)
   
  +
数字に関してはもっと面白いものが見られます。
Things get more interesting for numbers.
 
   
  +
<tt>
Prelude> :t <hask>42</hask>
 
<hask>42 :: (Num t) => t</hask>
+
:Prelude> :t <hask>42</hask>
Prelude> :t <hask>42.0</hask>
+
:<hask>42 :: (Num t) => t</hask>
<hask>42.0 :: (Fractional t) => t</hask>
+
:Prelude> :t <hask>42.0</hask>
Prelude> :t <hask>gcd 15 20</hask>
+
:<hask>42.0 :: (Fractional t) => t</hask>
<hask>gcd 15 20 :: (Integral t) => t</hask>
+
:Prelude> :t <hask>gcd 15 20</hask>
  +
:<hask>gcd 15 20 :: (Integral t) => t</hask>
  +
</tt>
   
  +
これらの型は“型クラス”を用いています。つまり:
These types use "type classes." They mean:
 
   
* <hask>42</hask> can be used as any numeric type. (This is why I was able to declare <hask>5</hask> as either an <hask>Int</hask> or a <hask>Double</hask> earlier.)
+
* <hask>42</hask> はあらゆる数値型として使うことができます。(このおかげで<hask>5</hask><hask>Int</hask>としても<hask>Double</hask>としても宣言できたわけです)
  +
* <hask>42.0</hask> はどのような小数型にもなれますが、整数型にはなれません。
* <hask>42.0</hask> can be any fractional type, but not an integral type.
 
  +
* <hask>gcd 15 20</hask> (ちなみにこれは関数呼び出しです)はどのような整数型にもなれますが、小数型にはなれません。
* <hask>gcd 15 20</hask> (which is a function call, incidentally) can be any integral type, but not a fractional type.
 
   
  +
Haskellの“Prelude”(標準ライブラリのうち初期状態でimportされているモジュール)内には5種類の数値型があります。
There are five numeric types in the Haskell "prelude" (the part of the library you get without having to import anything):
 
   
* <hask>Int</hask> is an integer with at least 30 bits of precision.
+
* <hask>Int</hask> は少なくとも30ビットの精度の整数です
* <hask>Integer</hask> is an integer with unlimited precision.
+
* <hask>Integer</hask> は精度無制限の整数型です
* <hask>Float</hask> is a single precision floating point number.
+
* <hask>Float</hask> は単精度浮動小数点数です
* <hask>Double</hask> is a double precision floating point number.
+
* <hask>Double</hask> は倍精度浮動小数点数です
* <hask>Rational</hask> is a fraction type, with no rounding error.
+
* <hask>Rational</hask> は分数型で丸め誤差がありません
   
All five are '''instances''' of the <hask>Num</hask> type class. The first two are '''instances''' of <hask>Integral</hask>, and the last three are '''instances''' of <hask>Fractional</hask>.
+
これら5つはすべて <hask>Num</hask>型クラスの '''インスタンス''' です。最初の2つは<hask>Integral</hask> '''インスタンス''' で、残り3つは<hask>Fractional</hask>の '''インスタンス''' です。
   
  +
ごちゃまぜにしてみましょう。
Putting it all together,
 
   
  +
<tt>
Prelude> <hask>gcd 42 35 :: Int</hask>
 
  +
:Prelude> <hask>gcd 42 35 :: Int</hask>
7
 
  +
:7
Prelude> <hask>gcd 42 35 :: Double</hask>
 
  +
:Prelude> <hask>gcd 42 35 :: Double</hask>
 
  +
:&nbsp;
<interactive>:1:0:
 
  +
:<interactive>:1:0:
No instance for (Integral Double)
 
  +
:&nbsp;&nbsp;&nbsp;&nbsp;No instance for (Integral Double)
  +
</tt>
   
  +
最後に触れておいたほうがよい型は <hask>()</hask>で表されるもので "Unit" と呼ばれます。この型はたった一つの値をとり、やはり<hask>()</hask>と書かれ "Unit" と呼ばれます。
The final type worth mentioning here is <hask>()</hask>, pronounced "unit." It only has one value, also written as <hask>()</hask> and pronounced "unit."
 
   
  +
<tt>
Prelude> <hask>()</hask>
 
<hask>()</hask>
+
:Prelude> <hask>()</hask>
Prelude> :t <hask>()</hask>
+
:<hask>()</hask>
<hask>() :: ()</hask>
+
:Prelude> :t <hask>()</hask>
  +
:<hask>() :: ()</hask>
  +
</tt>
   
  +
これはC言語系の言語での<tt>void</tt>キーワードに似ています。もしなにも返り値を期待しない場合、I/Oアクションから<hask>()</hask>を返すことができます。
You can think of this as similar to the <tt>void</tt> keyword in C family languages. You can return <hask>()</hask> from an I/O action if you don't want to return anything.
 
   
 
== 構造化されたデータ ==
 
== 構造化されたデータ ==
   
  +
基本データ型は2つの方法で容易にまとめることができます。一つはリストで角括弧 [ ] で囲います。もう一つはタプルで丸括弧 ( ) で囲みます。
Basic data types can be easily combined in two ways: lists, which go in [square brackets], and tuples, which go in (parentheses).
 
   
  +
リストは同じ型の複数の値を保持する場合に使われます。
Lists are used to hold multiple values of the same type.
 
   
  +
<tt>
Prelude> <hask>[1, 2, 3]</hask>
 
[1,2,3]
+
:Prelude> <hask>[1, 2, 3]</hask>
  +
:[1,2,3]
Prelude> <hask>[1 .. 5]</hask>
 
  +
:Prelude> <hask>[1 .. 5]</hask>
[1,2,3,4,5]
 
  +
:[1,2,3,4,5]
Prelude> <hask>[1, 3 .. 10]</hask>
 
  +
:Prelude> <hask>[1, 3 .. 10]</hask>
[1,3,5,7,9]
 
  +
:[1,3,5,7,9]
Prelude> <hask>[True, False, True]</hask>
 
[True,False,True]
+
:Prelude> <hask>[True, False, True]</hask>
  +
:[True,False,True]
  +
</tt>
   
  +
文字列は単に文字のリストにすぎません。
Strings are just lists of characters.
 
   
  +
<tt>
Prelude> <hask>['H', 'e', 'l', 'l', 'o']</hask>
 
  +
:Prelude> <hask>['H', 'e', 'l', 'l', 'o']</hask>
"Hello"
 
  +
:"Hello"
  +
</tt>
   
  +
<hask>:</hask>演算子は要素をリストの先頭に追加します。(Lisp系言語でいうところの<tt>cons</tt>関数です)
The <hask>:</hask> operator appends an item to the beginning of a list. (It is Haskell's version of the <tt>cons</tt> function in the Lisp family of languages.)
 
   
  +
<tt>
Prelude> <hask>'C' : ['H', 'e', 'l', 'l', 'o']</hask>
 
  +
:Prelude> <hask>'C' : ['H', 'e', 'l', 'l', 'o']</hask>
"CHello"
 
  +
:"CHello"
  +
</tt>
   
  +
タプルは決まった数の値を保持できます。ただしそれぞれの型は異なっていても構いません。
Tuples hold a fixed number of values, which can have different types.
 
   
  +
<tt>
Prelude> <hask>(1, True)</hask>
 
(1,True)
+
:Prelude> <hask>(1, True)</hask>
  +
:(1,True)
Prelude> <hask>zip [1 .. 5] ['a' .. 'e']</hask>
 
  +
:Prelude> <hask>zip [1 .. 5] ['a' .. 'e']</hask>
[(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e')]
 
  +
:[(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e')]
  +
</tt>
   
  +
この例の最後で <hask>zip</hask>関数 が使われています。これは2つのリストを1つのタプルのリストにするライブラリ関数です。
The last example used <hask>zip</hask>, a library function that turns two lists into a list of tuples.
 
   
  +
型は予想どおり以下のようになります。
The types are probably what you'd expect.
 
   
  +
<tt>
Prelude> :t <hask>['a' .. 'c']</hask>
 
<hask>['a' .. 'c'] :: [Char]</hask>
+
:Prelude> :t <hask>['a' .. 'c']</hask>
Prelude> :t <hask>[('x', True), ('y', False)]</hask>
+
:<hask>['a' .. 'c'] :: [Char]</hask>
<hask>[('x', True), ('y', False)] :: [(Char, Bool)]</hask>
+
:Prelude> :t <hask>[('x', True), ('y', False)]</hask>
  +
:<hask>[('x', True), ('y', False)] :: [(Char, Bool)]</hask>
  +
</tt>
   
  +
リストはHaskellではとてもよく使われます。リストを操作する便利な関数がいくつもあります。
Lists are used a lot in Haskell. There are several functions that do nice things with them.
 
   
  +
<tt>
Prelude> <hask>[1 .. 5]</hask>
 
<hask>[1,2,3,4,5]</hask>
+
:Prelude> <hask>[1 .. 5]</hask>
Prelude> <hask>map (+ 2) [1 .. 5]</hask>
+
:<hask>[1,2,3,4,5]</hask>
<hask>[3,4,5,6,7]</hask>
+
:Prelude> <hask>map (+ 2) [1 .. 5]</hask>
Prelude> <hask>filter (> 2) [1 .. 5]</hask>
+
:<hask>[3,4,5,6,7]</hask>
<hask>[3,4,5]</hask>
+
:Prelude> <hask>filter (> 2) [1 .. 5]</hask>
  +
:<hask>[3,4,5]</hask>
  +
</tt>
   
  +
また整列されたペア(2つの要素を持つタプル)に対する便利な関数が2つあります。
There are two nice functions on ordered pairs (tuples of two elements):
 
   
  +
<tt>
Prelude> <hask>fst (1, 2)</hask>
 
<hask>1</hask>
+
:Prelude> <hask>fst (1, 2)</hask>
Prelude> <hask>snd (1, 2)</hask>
+
:<hask>1</hask>
<hask>2</hask>
+
:Prelude> <hask>snd (1, 2)</hask>
Prelude> <hask>map fst [(1, 2), (3, 4), (5, 6)]</hask>
+
:<hask>2</hask>
<hask>[1,3,5]</hask>
+
:Prelude> <hask>map fst [(1, 2), (3, 4), (5, 6)]</hask>
  +
:<hask>[1,3,5]</hask>
  +
</tt>
   
Also see [[how to work on lists]]
+
[[how to work on lists]]も参照してください。
   
== [[Function]] 定義 ==
+
== [[関数]]定義 ==
   
We wrote a definition of an [[Introduction to Haskell IO/Actions |IO action]] earlier, called <hask>main</hask>:
+
<hask>main</hask>と呼ばれる[[Introduction to Haskell IO/Actions |IO action]]の定義について先に触れました。
   
 
<haskell>
 
<haskell>
Line 222: Line 256:
 
</haskell>
 
</haskell>
   
  +
では次に、実際に<hask>factorial</hask>という関数の ''[[関数]]" 定義を書いてみることで、上の例を補ってみましょう。丁寧に書こうと思うので、モジュールヘッダも追加します。
Now, let's supplement it by actually writing a ''[[function]]'' definition and call it <hask>factorial</hask>. I'm also adding a module header, which is good form.
 
   
 
<haskell>
 
<haskell>
Line 236: Line 270:
 
</haskell>
 
</haskell>
   
Build again with <tt>ghc --make Test.hs</tt>. And,
+
<tt>ghc --make Test.hs</tt>と入力し再ビルドします。そして実行します。
   
 
$ ./Test
 
$ ./Test
Line 243: Line 277:
 
You're right!
 
You're right!
   
  +
階数が得られました。ビルトイン関数のように、<hask>factorial 5</hask>と括弧なしで関数が呼び出せました。
There's a function. Just like the built-in functions, it can be called as <hask>factorial 5</hask> without needing parentheses.
 
   
Now ask <tt>ghci</tt> for the [[type]].
+
今度は<tt>ghci</tt>を使って[[]]を調べてみましょう。
   
 
$ ghci Test.hs
 
$ ghci Test.hs
Line 253: Line 287:
 
<hask>factorial :: (Num a) => a -> a</hask>
 
<hask>factorial :: (Num a) => a -> a</hask>
   
  +
関数の型は引数の型とともに表され、その後に<hask> -> </hask>が来て結果の型が書かれます。(結果も型クラス<hask>Num</hask>となります)
Function types are written with the argument type, then <hask> -> </hask>, then the result type. (This also has the type class <hask>Num</hask>.)
 
   
  +
階数は場合分けを使うことで簡単にできます。
Factorial can be simplified by writing it with case analysis.
 
   
 
<haskell>
 
<haskell>
Line 264: Line 298:
 
== 便利な構文 ==
 
== 便利な構文 ==
   
A couple extra pieces of [[:Category:Syntax |syntax]] are helpful.
+
さらにいくつかの[[:Category:Syntax |syntax]]が便利です。
   
 
<haskell>
 
<haskell>
Line 274: Line 308:
 
</haskell>
 
</haskell>
   
  +
<hask>let</hask>式は一時的な名前を定義します。(ここでもレイアウトが使われています。好みによりますが、{ 中括弧 }とセミコロンによる区切りを使うこともできます)
The <hask>let</hask> expression defines temporary names. (This is using layout again. You could use {braces}, and separate the names with semicolons, if you prefer.)
 
   
 
<haskell>
 
<haskell>
Line 283: Line 317:
 
</haskell>
 
</haskell>
   
The <hask>case</hask> expression does a multi-way branch. The special label <hask>_</hask> means "anything else".
+
<hask>case</hask>式は複数の場合分けを行います。特別なラベル <hask>_</hask> "その他すべて"を表します。
   
 
== ライブラリを使う ==
 
== ライブラリを使う ==
   
  +
ここまでのチュートリアルでは[[Prelude]]の一部しか使ってきませんでした。PreludeはHaskellのどんなプログラムでも使うことができる関数のセットです。
Everything used so far in this tutorial is part of the [[Prelude]], which is the set of Haskell functions that are always there in any program.
 
   
The best road from here to becoming a very productive Haskell programmer (aside from practice!) is becoming familiar with other [[Applications and libraries | libraries]] that do the things you need. Documentation on the standard libraries is at [http://haskell.org/ghc/docs/latest/html/libraries/ http://haskell.org/ghc/docs/latest/html/libraries/]. There are modules there with:
+
ここから生産性の高いHaskellプログラマになるためには、あなたが必要とするPrelude以外の[[Applications and libraries | libraries]]について明るくなるのがよいです。標準ライブラリに関しては[http://haskell.org/ghc/docs/latest/html/libraries/ http://haskell.org/ghc/docs/latest/html/libraries/]にあります。モジュールは以下のものがあります。
   
 
* [[Applications and libraries/Data structures |Useful data structures]]
 
* [[Applications and libraries/Data structures |Useful data structures]]
Line 315: Line 349:
 
</haskell>
 
</haskell>
   
  +
<hask>import</hask>は<hask>Data.Map</hask>にあるコードを使うことを宣言していて、それらは<hask>M</hask>という別名を使うことが定義されています。(ここで行っていることは必要なことです。なぜならいくつかの関数はPrelude内の関数と同じ名前を持っているからです。たいていのライブラリでは<hask>as</hask>の部分は必要ありません。)
The <hask>import</hask> says to use code from <hask>Data.Map</hask> and that it will be prefixed by <hask>M</hask>. (That's necessary because some of the functions have the same names as functions from the prelude. Most libraries don't need the <hask>as</hask> part.)
 
   
  +
もし標準ライブラリにないものを必要とする場合は、 http://hackage.haskell.org/packages/hackage.html かこのWikiの[[applications and libraries]]のページを見てください。これらは多くの方々がHaskellのために書いたたくさんのライブラリを集めたページです。ライブラリを手元に落としてきたら、展開してそのディレクトリに入って以下を実行してください:
If you want something that's not in the standard library, try looking at http://hackage.haskell.org/packages/hackage.html or this wiki's [[applications and libraries]] page. This is a collection of many different libraries written by a lot of people for Haskell. Once you've got a library, extract it and switch into that directory and do this:
 
   
 
runhaskell Setup configure
 
runhaskell Setup configure
Line 323: Line 357:
 
runhaskell Setup install
 
runhaskell Setup install
   
  +
UNIXでは最後の<tt>runhaskell Setup install</tt>を実行するためにrootになる必要があります。
On a UNIX system, you may need to be root for that last part.
 
   
 
== 10分以上かかるので省いたトピック ==
 
== 10分以上かかるので省いたトピック ==
   
 
* [[:Category:Language | Advanced data types]]
 
* [[:Category:Language | Advanced data types]]
  +
** 数学的なリスト
** Arithmetic lists
 
 
** [[List comprehension]]s
 
** [[List comprehension]]s
 
** [[Type#Type and newtype | Type synonyms]]
 
** [[Type#Type and newtype | Type synonyms]]
Line 337: Line 371:
 
** [[Infix operator |(+) and `foo`]]
 
** [[Infix operator |(+) and `foo`]]
 
** [[Fixity declaration]]s
 
** [[Fixity declaration]]s
  +
* 発展的な関数
* Advanced functions
 
 
** [[Currying]]
 
** [[Currying]]
 
** [[Lambda abstraction]]s
 
** [[Lambda abstraction]]s
Line 343: Line 377:
 
* [[:Category:Monad |Monads]]
 
* [[:Category:Monad |Monads]]
 
* [[Tutorials/Programming Haskell/String IO |File I/O]]
 
* [[Tutorials/Programming Haskell/String IO |File I/O]]
  +
** ファイルの読み込み
** Reading files
 
  +
** ファイルの書き込み
** Writing Files
 
   
 
[[Category:Tutorials]]
 
[[Category:Tutorials]]

Revision as of 15:14, 28 March 2012

概要

Haskellは関数型で(つまりすべてが関数呼びだしで処理される)、静的な暗黙的型付けで(はコンパイラによって確認され、明示的に宣言する必要はない)、遅延評価(必要となるまで処理されない)の言語です。系統が近い言語として最も人気のあるのはおそらくML系の言語でしょう。(MLは遅延評価ではないですが)

最も普及しているHaskellのコンパイラは GHC です。GHCは http://www.haskell.org/ghc/download.html からダウンロードできます。GHCのバイナリは GNU/Linux FreeBSD MacOSWindowsSolarisで動作します。GHCをインストールすると、ghc ghciという2つのプログラムが入っているのが確認できます。最初のghcの方はHaskellのライブラリやアプリケーションをバイナリコードにコンパイルします。 ghciはインタプリタで、Haskellコードを書いてすぐに結果を得ることができる環境です。

簡単な数式

たいていの数式は直接ghciに入力して計算結果を得ることができます。Prelude>はGHCiのデフォルトのプロンプトです。

Prelude> 3 * 5
15
Prelude> 4 ^ 2 - 1
15
Prelude> (1 - 5)^(3 * 2 - 4)
16

文字列はダブルクォート(二重引用符)で囲みます。文字列の結合をするときは++を使います。

Prelude> "Hello"
"Hello"
Prelude> "Hello" ++ ", Haskell"
"Hello, Haskell"

関数を呼び出すときは関数の後に直接引数を並べて行います。関数呼び出しに括弧は必要ありません。こんな感じです:

Prelude> succ 5
6
Prelude> truncate 6.59
6
Prelude> round 6.59
7
Prelude> sqrt 2
1.4142135623730951
Prelude> not (5 < 3)
True
Prelude> gcd 21 14
7

コンソール

I/Oアクションはコンソールからの入出力を行うのに使います。よくある例は:

Prelude> putStrLn "Hello, Haskell"
Hello, Haskell
Prelude> putStr "No newline"
No newlinePrelude> print (5 + 4)
9
Prelude> print (1 < 2)
True

putStr関数 と putStrLn関数 は文字列をターミナルに出力します。print関数はどんな型の値でも出力します。(文字列をprintするときは、引用符が前後につきます)

ひとつの式の中で複数の I/O アクションを使いたい場合は、doブロックを使います。アクションはセミコロンで区切られます。

Prelude> do { putStr "2 + 2 = " ; print (2 + 2) }
2 + 2 = 4
Prelude> do { putStrLn "ABCDE" ; putStrLn "12345" }
ABCDE
12345

読み込みは getLineStringを返します)かreadLn(どんな型の値でも返します)でできます。<-という記号はI/Oアクションの結果に名前を付けるために使います。

Prelude> do { n <- readLn ; print (n^2) }
4
16

(4が入力で16が結果です。)

別の書き方でdoブロックを書くこともできます。中括弧やセミコロンを使わずに、インデントでブロックと式の区切りを表します。ghciでは書けないので、ソースファイル(例えばTest.hs)に書いてビルドしてみましょう。

main = do putStrLn "What is 2 + 2?"
          x <- readLn
          if x == 4
              then putStrLn "You're right!"
              else putStrLn "You're wrong!"

ビルドは ghc --make Test.hs でできます。実行ファイル Test ができるはずです。(WindowsではTest.exeとなります)ここでif式も一緒に習得できてしまいますね。

doの直後の最初の空白でない文字は特別な文字です。上の例の場合ではputStrLnの先頭のpがそれです。doブロック内のすべての行はそのpと同じ列から開始します。もしインデントがより深ければ、それ以前の行の一部となります。逆にインデントが浅ければ、doブロックはそこで終わります。これは“レイアウト”と呼ばれ、Haskellでは、いつも行の区切り文字や中括弧を使うのは面倒なので、代わりにレイアウトを使います。(then句とelse句はこれが理由でifよりインデントが深くなければならないのです。もしifと同じ列から開始した場合、ifと別の行と解釈されてしまって、エラーとなります。)

(Note: レイアウトを使う場合はインデントにタブを用いないでください。技術的にはタブが8文字であれば動作しますが、おすすめできません。また中には使う人もいるかもしれませんが、プロポーショナルフォントを使うこともおすすめしません。

簡単な型

これまで、宣言に関して全く触れてきませんでした。それはHaskellが型推論を行うからです。一般的に型宣言はしたい場合以外はする必要がありません。型宣言をする場合は::を使って行います。

Prelude> 5 :: Int
5
Prelude> 5 :: Double
5.0

Haskellでは (そして後で触れる型クラス)は常に大文字から開始します。変数は常に小文字から始まります。これは言語仕様であり、命名規則(naming convention)ではありません。

ghciを使って、ある値がどんな型かを確認することもできます。普段、自分では型宣言をしないので、この機能は役に立ちます。

 Prelude> :t True
 True :: Bool
 Prelude> :t 'X'
 'X' :: Char
 Prelude> :t "Hello, Haskell"
 "Hello, Haskell" :: [Char]

(上の例を見て気づいたように、[Char]Stringの別名です。あとでをsection on listsを見てみましょう)

数字に関してはもっと面白いものが見られます。

Prelude> :t 42
42 :: (Num t) => t
Prelude> :t 42.0
42.0 :: (Fractional t) => t
Prelude> :t gcd 15 20
gcd 15 20 :: (Integral t) => t

これらの型は“型クラス”を用いています。つまり:

  • 42 はあらゆる数値型として使うことができます。(このおかげで5IntとしてもDoubleとしても宣言できたわけです)
  • 42.0 はどのような小数型にもなれますが、整数型にはなれません。
  • gcd 15 20 (ちなみにこれは関数呼び出しです)はどのような整数型にもなれますが、小数型にはなれません。

Haskellの“Prelude”(標準ライブラリのうち初期状態でimportされているモジュール)内には5種類の数値型があります。

  • Int は少なくとも30ビットの精度の整数です
  • Integer は精度無制限の整数型です
  • Float は単精度浮動小数点数です
  • Double は倍精度浮動小数点数です
  • Rational は分数型で丸め誤差がありません

これら5つはすべて Num型クラスの インスタンス です。最初の2つはIntegralインスタンス で、残り3つはFractionalインスタンス です。

ごちゃまぜにしてみましょう。

Prelude> gcd 42 35 :: Int
7
Prelude> gcd 42 35 :: Double
 
<interactive>:1:0:
    No instance for (Integral Double)

最後に触れておいたほうがよい型は ()で表されるもので "Unit" と呼ばれます。この型はたった一つの値をとり、やはり()と書かれ "Unit" と呼ばれます。

Prelude> ()
()
Prelude> :t ()
() :: ()

これはC言語系の言語でのvoidキーワードに似ています。もしなにも返り値を期待しない場合、I/Oアクションから()を返すことができます。

構造化されたデータ

基本データ型は2つの方法で容易にまとめることができます。一つはリストで角括弧 [ ] で囲います。もう一つはタプルで丸括弧 ( ) で囲みます。

リストは同じ型の複数の値を保持する場合に使われます。

Prelude> [1, 2, 3]
[1,2,3]
Prelude> [1 .. 5]
[1,2,3,4,5]
Prelude> [1, 3 .. 10]
[1,3,5,7,9]
Prelude> [True, False, True]
[True,False,True]

文字列は単に文字のリストにすぎません。

Prelude> ['H', 'e', 'l', 'l', 'o']
"Hello"

:演算子は要素をリストの先頭に追加します。(Lisp系言語でいうところのcons関数です)

Prelude> 'C' : ['H', 'e', 'l', 'l', 'o']
"CHello"

タプルは決まった数の値を保持できます。ただしそれぞれの型は異なっていても構いません。

Prelude> (1, True)
(1,True)
Prelude> zip [1 .. 5] ['a' .. 'e']
[(1,'a'),(2,'b'),(3,'c'),(4,'d'),(5,'e')]

この例の最後で zip関数 が使われています。これは2つのリストを1つのタプルのリストにするライブラリ関数です。

型は予想どおり以下のようになります。

Prelude> :t ['a' .. 'c']
['a' .. 'c'] :: [Char]
Prelude> :t [('x', True), ('y', False)]
[('x', True), ('y', False)] :: [(Char, Bool)]

リストはHaskellではとてもよく使われます。リストを操作する便利な関数がいくつもあります。

Prelude> [1 .. 5]
[1,2,3,4,5]
Prelude> map (+ 2) [1 .. 5]
[3,4,5,6,7]
Prelude> filter (> 2) [1 .. 5]
[3,4,5]

また整列されたペア(2つの要素を持つタプル)に対する便利な関数が2つあります。

Prelude> fst (1, 2)
1
Prelude> snd (1, 2)
2
Prelude> map fst [(1, 2), (3, 4), (5, 6)]
[1,3,5]

how to work on listsも参照してください。

関数定義

mainと呼ばれるIO actionの定義について先に触れました。

main = do putStrLn "What is 2 + 2?"
          x <- readLn
          if x == 4
              then putStrLn "You're right!"
              else putStrLn "You're wrong!"

では次に、実際にfactorialという関数の 関数" 定義を書いてみることで、上の例を補ってみましょう。丁寧に書こうと思うので、モジュールヘッダも追加します。

module Main where

factorial n = if n == 0 then 1 else n * factorial (n - 1)

main = do putStrLn "What is 5! ?"
          x <- readLn
          if x == factorial 5
              then putStrLn "You're right!"
              else putStrLn "You're wrong!"

ghc --make Test.hsと入力し再ビルドします。そして実行します。

 $ ./Test
 What is 5! ?
 120
 You're right!

階数が得られました。ビルトイン関数のように、factorial 5と括弧なしで関数が呼び出せました。

今度はghciを使ってを調べてみましょう。

 $ ghci Test.hs
 << GHCi banner >>
 Ok, modules loaded: Main.
 Prelude Main> :t factorial
 factorial :: (Num a) => a -> a

関数の型は引数の型とともに表され、その後に->が来て結果の型が書かれます。(結果も型クラスNumとなります)

階数は場合分けを使うことで簡単にできます。

factorial 0 = 1
factorial n = n * factorial (n - 1)

便利な構文

さらにいくつかのsyntaxが便利です。

secsToWeeks secs = let perMinute = 60
                       perHour   = 60 * perMinute
                       perDay    = 24 * perHour
                       perWeek   =  7 * perDay
                   in  secs / perWeek

let式は一時的な名前を定義します。(ここでもレイアウトが使われています。好みによりますが、{ 中括弧 }とセミコロンによる区切りを使うこともできます)

classify age = case age of 0 -> "newborn"
                           1 -> "infant"
                           2 -> "toddler"
                           _ -> "senior citizen"

case式は複数の場合分けを行います。特別なラベル _ は"その他すべて"を表します。

ライブラリを使う

ここまでのチュートリアルではPreludeの一部しか使ってきませんでした。PreludeはHaskellのどんなプログラムでも使うことができる関数のセットです。

ここから生産性の高いHaskellプログラマになるためには、あなたが必要とするPrelude以外の librariesについて明るくなるのがよいです。標準ライブラリに関してはhttp://haskell.org/ghc/docs/latest/html/libraries/にあります。モジュールは以下のものがあります。

module Main where

import qualified Data.Map as M

errorsPerLine = M.fromList
    [ ("Chris", 472), ("Don", 100), ("Simon", -5) ]

main = do putStrLn "Who are you?"
          name <- getLine
          case M.lookup name errorsPerLine of
              Nothing -> putStrLn "I don't know you"
              Just n  -> do putStr "Errors per line: "
                            print n

importData.Mapにあるコードを使うことを宣言していて、それらはMという別名を使うことが定義されています。(ここで行っていることは必要なことです。なぜならいくつかの関数はPrelude内の関数と同じ名前を持っているからです。たいていのライブラリではasの部分は必要ありません。)

もし標準ライブラリにないものを必要とする場合は、 http://hackage.haskell.org/packages/hackage.html かこのWikiのapplications and librariesのページを見てください。これらは多くの方々がHaskellのために書いたたくさんのライブラリを集めたページです。ライブラリを手元に落としてきたら、展開してそのディレクトリに入って以下を実行してください:

 runhaskell Setup configure
 runhaskell Setup build
 runhaskell Setup install

UNIXでは最後のrunhaskell Setup installを実行するためにrootになる必要があります。

10分以上かかるので省いたトピック

Languages: en zh/cn ja