のびのびなHaskell日記

2006-06-23

filter関数

 -- ファイル名:foo.hs
main = print $ filter isDeveloper ["Martin Fowler","Joel Spolsky","Zico"]
isDeveloper :: String -> Bool
isDeveloper c = if c == "Zico" then False else True
実行結果
D:\Development\PracticeHaskell>foo
["Martin Fowler","Joel Spolsky"]

リスト["Martin Fowler","Joel Spolsky","Zico"]のそれぞれの要素にisDeveloper関数適用し、その結果Trueを返してくれる要素だけをあつめたリストが返ってきます。

トラックバック - http://haskell.g.hatena.ne.jp/NobiNobiKota/20060623

2006-06-20

unlines関数

Prelude> unlines ["Oasis","Maroon 5","Dido"]
"Oasis\nMaroon 5\nDido\n"

Prelude> unlines []
""
Prelude> unlines ["Java"]
"Java\n"
Prelude> unlines ["Java\n"]
"Java\n\n"

take関数

Prelude> take 3 ["Oasis","Maroon 5","Dido"]
["Oasis","Maroon 5","Dido"]

Prelude> take 2 ["Oasis","Maroon 5","Dido"]
["Oasis","Maroon 5"]

Prelude> take 1 ["Oasis","Maroon 5","Dido"]
["Oasis"]

Prelude> take 0 ["Oasis","Maroon 5","Dido"]
[]

take関数の第一引数に0を指定した場合は空要素が返ってくるみたいですね。

Prelude> take 1000 ["Oasis","Maroon 5","Dido"]
["Oasis","Maroon 5","Dido"]

take関数の第二引数リストよりも大きな値を第一引数に指定した場合は第二引数で指定したリストが全て返ってくるみたいですね。


lines関数

ghciを起動してlines関数を動かしてみました。

Prelude> lines "Oasis\nMaroon 5\nDido"
["Oasis","Maroon 5","Dido"]

フツケル 45頁 headコマンド写経

淡々写経します。

main = do cs <- getContents
          putStr $ firstNLines 10 cs

firstNLines n cs = unlines $ take n $ lines cs

標準入力で得た内容を変数csに束縛

firstNLines関数の第一引数に10を、第二引数変数csが保持する文字列を渡す

firstNLines関数は10とcsを受け取る

cs(文字列)に対してlinesを適用すると、文字列のリストが返ってくる

take 10 文字列のリスト」を実行すると、文字列のリストから先頭10件のみを取得した文字列のリストが返ってくる

文字列のリストにunlines関数適用すると文字列が返ってくる

その文字列を呼び出し元に返し、そしてそれにputStr関数適用しているのでコンソールには文字列が表示される。その文字列は標準入力された文字列の先頭から10行分を出力したものである。

トラックバック - http://haskell.g.hatena.ne.jp/NobiNobiKota/20060620

2006-06-16

1から10までの和 その2

mysum :: Int -> Int
mysum 1 = 1
mysum x = x + mysum (x-1)
main = print $ mysum 10

上のコードの3行目の括弧をはずしコンパイル後、生成された実行ファイルを実行するとエラーが出ます。

mysum :: Int -> Int
mysum 1 = 1
mysum x = x + mysum x-1 --括弧をはずしてコンパイル
main = print $ mysum 10
 --実行時エラー
Stack space overflow: current size 8388608 bytes.
Use `+RTS -Ksize' to increase it.

なんでだろう(^_^;)

どちらが大きい?

フツケルP174のガードを使って、二つの整数xとyに関して、xがyより大きい時は、x is greater than yと表示し、xがyより小さい時はx is less than yと表示されるコードを書いてみました。

mysum :: Int -> Int -> String
mysum x y
 | x > y = "x is greater than y"
 | x < y = "x is less than y"
main = putStrLn $ mysum 2 100
 --実行結果
x is less than y

main = putStrLn $ mysum 2 100を手動デバッグ

mysum 2 100

x = 2,y = 100

最初の条件文の評価:x > y => false 次の条件文へ進む

次の条件文の評価:x < y => True "x is less than y"という文字列を呼び出し元へ返す

main = putStrLn "x is less than y"

"x is less than y"という文字列にputStrLn関数適用したので、コンソールに"x is less than y"という文字列が表示される。

1から10までの和 その1

1から10までの和を求める方法を、id:muscovyduckさんに教えて頂いたので早速試してみました。

mysum :: Int -> Int
mysum 1 = 1
mysum x = x + mysum(x-1)
main = print $ mysum 10

手動でデバッグしてみました。

mysum 10 = 10 + mysum(10 - 1)

10 + (mysum 9)

10 + (9 + mysum 8)

(10 + 9) + (mysum 8)

(10 + 9) + (8 + mysum 7)

(10 + 9 + 8) + mysum 7

(10 + 9 + 8) + (7 + mysum 6)

(10 + 9 + 8 + 7) + mysum 6

(10 + 9 + 8 + 7) + (6 + mysum 5)

(10 + 9 + 8 + 7 + 6) + mysum 5

(10 + 9 + 8 + 7 + 6) + (5 + mysum 4)

(10 + 9 + 8 + 7 + 6 + 5) + mysum 4

(10 + 9 + 8 + 7 + 6 + 5) + (4 + mysum 3)

(10 + 9 + 8 + 7 + 6 + 5 + 4 ) + mysum 3

(10 + 9 + 8 + 7 + 6 + 5 + 4 ) + (3 + mysum 2)

(10 + 9 + 8 + 7 + 6 + 5 + 4 + 3) + mysum 2

(10 + 9 + 8 + 7 + 6 + 5 + 4 + 3) + (2 + mysum 1)

(10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 ) + mysum 1

(10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 ) + 1

10 + 9 + 8 + 7 + 6 + 5 + 4 + 3 + 2 + 1

==> 55

10にmysum関数適用することによって1から55までの和を求めることが出来るということが分かりました。

haskonhaskon2006/06/17 00:05haskellは関数呼び出しの結合のほうが強いからだと思います。
mysum x = x + mysum x-1
では、
mysum x = x + (mysum x) - 1
と、同じ結果になってしまいます
mysum x = x + mysum $ x -1
なら、うまくいくと思いますよ

muscovyduckmuscovyduck2006/06/17 00:08カッコを外すと問題が生じるのは、'-'(マイナス)も実は関数(二項演算子)だからです。関数適用の優先順位については、153ページあたりに解説があります。156ページに「関数適用の優先順位はHaskellを学習するさいの壁になりがち」とある通りですねえ。

taninswtaninsw2006/06/17 07:54mysum x = x + mysum $ x -1
は型エラーになります.$は優先順位が0の関数なので
mysum x = (x + mysum) $ (x -1)
と同じことになります。

NobiNobiKotaNobiNobiKota2006/06/17 10:24>haskonさん、muscovyduckさん、taninswさん、コメントありがとうございます(^^)
アドバイス頂いたとおり以下のようにコードを修正しましたが、依然としてエラーが出ています。
mysum :: Int -> Int
mysum 1 = 1
mysum x = x + mysum $ x -1
main = print $ mysum 10
<上のコードをコンパイルしたときに表示されたエラー>
Expecting a function type, but found `a'
Expected type: Int
Inferred type: Int -> Int
In the second argument of `(+)', namely `mysum'
In the first argument of `($)', namely `x + mysum'
因みにmysum関数のところのみを修正した以下のコードもコンパイルしてみました。
mysum :: Int -> Int
mysum 1 = 1
mysum x = (x + mysum) $ (x-1)
main = print $ mysum 10
<実行したときに表示されたエラー>
Expecting a function type, but found `a'
Expected type: Int
Inferred type: Int -> Int
In the second argument of `(+)', namely `mysum'
In the first argument of `($)', namely `(x + mysum)'
二つのエラーを見比べてみると
In the first argument of `($)', namely `(x + mysum)'
この箇所の(x + mysum)の括弧の有無を除けば同じエラーが表示されていますね。
フツケルの153ページあたりも後ほど読んでみたいと思います(^^)

muscovyduckmuscovyduck2006/06/18 00:11NobiNobiKotaさん>
いえ、そうではなくて‥‥。
taninswさんは、次のことをおっしゃっているのだと思います。
・「mysum x = x + mysum $ x -1」と書くと「型エラーになります」。
・なぜなら、「mysum x = (x + mysum) $ (x -1)」と解釈されるからです。
というわけで「mysum x = x + mysum $ x -1」も「mysum x = (x + mysum) $ (x -1)」もダメで、「mysum x = x + mysum (x - 1)」と書かないとうまく動かないのです。

taninswtaninsw2006/06/18 01:59その通りです。
すいません、言葉足らずでした。

NobiNobiKotaNobiNobiKota2006/06/18 22:11私のほうこそ勘違いして済みませんでした(汗)

トラックバック - http://haskell.g.hatena.ne.jp/NobiNobiKota/20060616

2006-06-15

二章から読み直す

6章まで駆け足で読みましたが、なんだかよく分からなくなってきたので2章に戻り、ゆっくりと写経してみます。

フツケル 24頁から27頁 写経

main = putStrLn "Hello, Haskell!"
Hello, Haskell!

putStrLn "Hello, Haskell!"はputStrLn関数に"Hello, Haskell!"という文字列を渡すというのではなく、文字列"Hello, Haskell!"に対して関数putStrLnを適用するとHaskellでは言う。文字列に関数適用するという言葉を使った言語を学ぶのは初めて。

ここで使われているmainは関数ではなく変数である。変数mainの定義をしています。mainと書いてあるとmain関数だと思ってしまうが、ここでは変数mainの定義をしていて、その変数mainの値が右辺とのこと。

putStrLn "Hello, Haskell!"は、Hello, Haskell!という文字列を出力するアクションであるということを学ぶが、アクションが何なのかは現時点では不明

トラックバック - http://haskell.g.hatena.ne.jp/NobiNobiKota/20060615

2006-06-14

loopがないので悩み中

Haskellにはloopがない。loopなしで1から10までの和見たいな計算をどうやって行えば良いのだろうと先程から色々と試していますが、どれもこれも上手くいきません(^_^;)フツケルのどこら辺を読めば、ループ計算できるようになるんでしょうか(笑)

遅延評価

フツケル6章の基本的な値の途中を読んでいるところです。このところ帰宅時間が遅く帰宅後疲れて眠ってしまう(^_^;)

5章の遅延処理は、遅延処理がどういうものなのかというのは分かった程度の理解度

最近電車でフツケルを読むだけでコードを書いていないので、少し前に戻ってコードを書きたいと思います。

大文字と小文字区別

 --(1)コンパイル通る
main = print $ square 6
square :: Int -> Int
square n = n * n
 --(2)コンパイル通らない
main = print $ square 6
square :: INT -> Int
square n = n * n

(2)をコンパイルした表示されたエラー

square.hs:3:10: Not in scope: type constructor or class `INT'
 --(3)コンパイル通らない
main = print $ square 6
square :: inT -> Int
square n = n * n

(3)をコンパイルした際表示されたエラー

square.hs:4:11:
    Couldn't match the rigid variable `inT' against `Int'
      `inT' is bound by the type signature for `square'
      Expected type: Int
      Inferred type: inT
    In the expression: n * n
    In the definition of `square': square n = n * n

IntをINTやinTと間違って書いても、表示されるエラーは異なるんですね。

muscovyduckmuscovyduck2006/06/16 12:45Haskellでプログラムを書いていてloopしたいような場面に遭遇したときは、再帰が使えると思います。
たとえば「1から10までの和」なら、次のとおりです。
--
mysum 1 = 1
mysum x = x + mysum (x - 1)
main = print $ mysum 10
--
ちなみに「xからyの和」だと、ガードを使って次のように書けます。3から10の和なら、次のとおりです。
--
mysum x y
| x == y = x
| otherwise = y + mysum x (y - 1)
main = print $ mysum 3 10
--

NobiNobiKotaNobiNobiKota2006/06/16 21:38>muscovyduckさん
こんばんは(^^)早速教えていただいた通りにコードを書いてみたところ
1から10までの和を求めることが出来ました!ありがとうございました(感謝)

トラックバック - http://haskell.g.hatena.ne.jp/NobiNobiKota/20060614

2006-06-12

ふつける P90を読んでいます。

head関数

head :: [a] -> a

Prelude> head [5050,1984]
5050
Prelude> head ["Van Halen","Oasis"]
"Van Halen"

head関数は上記のようにリストの最初の要素を返してくれる関数です。

[String] -> String

引数Stringリストであれば、Stringが返ってきます。

[Int] -> Int

引数がIntのリストであれば、Intが返ってきます。

Prelude> head []
			
Exception: Prelude.head: empty list
Prelude> head ""
Exception: Prelude.head: empty list

headの引数が空リストの時はExceptionが発生します。

""は空文字列なので、空文字のリストとして表すことが出来ます。従いまして""ととは同値ですから、head ?でExceptionが発生するなら、head ""でもExceptionは発生するのは自然ですね。

トラックバック - http://haskell.g.hatena.ne.jp/NobiNobiKota/20060612

2006-06-11

ふつうのHaskellプログラミング

まずは自己紹介から。はじめましてid:NobiNobiKotaと申します。

一週間前ぐらい前に「ふつうのHaskellプログラミング」を購入したのでHaskell日記を始めてみたいと思います。Haskellに関しては全くの初心者ですし(他の言語初心者レベル)、毎日更新は出来ませんが宜しくお願い致しますm(__)m

全くの余談ですが昨日参加したRuby会議の懇親会で著者の青木さんに、持参したフツケル本へサインして頂きました\(^o^)/青木さん、サインありがとうございました(大感謝)&自己紹介もせずにサインを求めてしまって済みませんでした(汗)

フツケル 84頁の写経

フツケル84頁に以下のようなコードが出てきます。

import System
main = do args <- getArgs
          putStrLn $ unwords args

このimportというのを見て、importの行を削除し、System.getArgsのように(Javaインポート宣言を省略して、java.util.Dateとするように)変更して、以下のコードがコンパイル出来るかなと試してみました。

main = do args <- System.getArgs
          putStrLn $ unwords args

結果はコンパイル失敗でした(^_^;)

echo.hs:2:18: Not in scope: `System.getArgs'

因みにimport宣言のところを生かした以下のコードはコンパイルは通ります。

import System
main = do args <- System.getArgs
          putStrLn $ unwords args

友人とunwords関数で遊んでみる

先ほど友人とYahooチャットを使ってunwords関数で遊んでみた時のチャットログです。こんなの掲載してどうするんだって(汗)

因みにKは私、Xは友人

K: unwords関数で遊んで見ましょう
X: はい。
K: 関数で遊ぶ時は、ghciを起動して遊びます
X: そうなんだ。
K: ですです
K: 例えば、ghciを起動するでしょ
K: で
K: unwords ["I","Love","Java"]と心の中の気持ちをコンソールにぶつけてください(w
X: やりました。通じたようです。
K: Javaへの愛が通じて良かったです(笑)
X: まだ、残っていたようです。
K: Javaへの愛を時折思い出すためにも、定期的にghciを起動してunwords ["I","Love","Java"]を実行してください(笑
X: そうします。いいのかな、こんなんで。
K: いいんです!
トラックバック - http://haskell.g.hatena.ne.jp/NobiNobiKota/20060611