Haskell

Project Eulerが楽しい

in

Haskellの勉強だと思ってProject Eulerはじめたんですが、思いの外ハマってしまって嬉し楽しです。年明けから始めて二月にようやくレベル1まで到達しました。一応、すべての問題をHaskellで解きました。苦労したのはProblem23で、先にC++のプログラムを作成して答えはわかっているのにHaskellでうまく書けずどうやってもStack OverFlow***。再帰再帰がうまくないのはわかっていたので$!とかseqとかいろいろやってみましたがダメ。で、最終的にはData.Arrayを再構築しながら切り抜けました。この方法は、google先生の助けをかりたのですがコピペはしていないのでマイルールには抵触しないです。σ(^_^;)?

この先、問題が難しくなることを考えればどう考えても全問解答まで一年以上かかる計算ですが、楽しくて止められません。

プログラミングHaskell (第八章の練習問題)

in

翻訳片手に再びトライ。この章にあるdo構文は、ghci環境では動作しないこともあり等価の(>>=)を使い(原著p77,翻訳p93参照)ます。また、ghci環境下ではPrelude.>>=と重複するためすべてMainの修飾子を付加しています。

8.10 (1) int::Parser Intを定義せよ

プログラミングHaskell (第八章の練習問題)の前に

in

八章は原著で玉砕していて僕にとっては鬼門です。練習問題に入る前に原著を読んだときに躓いたことを整理しておくと、躓きはテキストの例題にある1番目と3番目をペアで返すpのコード

p = do x <- item'
       _ <- item'
       y <- item'
       return' (x,y)

を入力してもエラーになって先に進めなかったこと。このこと自体はググってみたら、

p = item Main.>>= \x ->
    item Main.>>= \_ ->
    item Main.>>= \y ->
    return' (x,y)

のように、(>>=)を使えばうまくコードを実行できることはわかったのですが、肝心の実装が理解できず苦しみました。例えば、`parse item "abcde"`の結果が('a',"bcde")であるなら、`p "abcde"`は、

return' (('a',"bcde"),('c',"de"))

じゃないの?というところから抜け出せずにい(た|る)わけです。

プログラミングHaskell (第七章の練習問題)

in

7.8 (1) [f x|x <- xs, p x]をmapとfilterを使って書き直すとどうなるか?

a'::[Int]
a' = map f (filter p xs)
  where
    xs = [1,3..50]
    f  = (*2)
    p  = (<18)

まあ、これはいいかな。

7.8 (2) 標準ライブラリの定義をみないでall,any,takeWhile,dropwhileを定義せよ

プログラミングHaskell (第六章の練習問題)

in

新年おめでとうございます。本年もボチボチとよろしくおつきあいいただける僕としてもうれしいです。

6.8 (1) 負でない整数に対する累乗演算子を定義せよ。またその定義で2^3を簡約せよ

(#) :: Int -> Int -> Int
m # 0 = 1
m # (n + 1) = m * (m # n)

(Prelude.^)とバッティングするので(#)にしてます。

 2#3
 = 2*(2#2)
 = 2*2*(2#1) 
 = 2*2*2*(2#0) 
 = 2*2*2*1
 = 8

ところで、僕の解答ですが括弧がないです。一見したときは正しいと思ったのですがこの間違いは大きい気がします。結果の8は同じですが、問題の意図からすれば零点といってもいいくらい。

プログラミングHaskell (第五章の練習問題・シーザーの暗号)

in

5.7 (8) シーザー暗号のプログラムを大文字も扱えるように変更せよ

だんだん、プログラムらしくなってきました。問題のシーザー暗号のプログラムがどこまでのことを指すのか今ひとつわかりませんでしたが、crackの箇所は大文字の出現頻度がわからないのでとりあえず、暗号化するところまで。まず、let2intを改造して大文字もint変換できるように修正します。

プログラミングHaskell (第五章の練習問題)

in

5.7 (1) リスト内包表記を使って1から100の二乗の和を計算する式を考えよ

sum' = sum[x^2 | x <- [1..100]]

まぁまぁ、このあたりは...ね。

5.7 (2) replicateをリスト内包表記を使って定義せよ

プログラミングHaskell (第四章の練習問題)

in

4.8 (1) 偶数の長さをもつリストを半分に分割するhalve::[a] -> ([a],[a])を定義せよ

havle::[a] -> ([a],[a])
havle xs = (take n xs, drop n xs)
where n = length xs `div` 2

リストの長さが奇数でもOKだが?例外をスローすべきなのか?この章までではエラー処理についてはなにも言及されていないのでこのままで。解答には、

halve xs = splitAt (length xs `div` 2) xs

というのもありました。通常、こちらを使うべきですね。

プログラミングHaskell (第三章の練習問題)

in

まだまだ、調子よく進んでますが...

3.11 (1) 以下の値の型は何か?

a :: [Char]
a = ['a','b','c']
b :: (Char,Char,Char)
b = ('a','b','c')
c :: [(Bool,Char)]
c = [(False,'o'),(True,'l')]
d :: ([Bool],[Char])
d = ([False,True],['o','l'])
e :: [([a]->[a])]
e = [tail,init,reverse]

最後の問題は、括弧はつけなくとも大丈夫だとは思いましたがあえて関数のリストということであえてつけてみましたが冗長なのでむしろわかりにくくなるかもしれないので減点。

プログラミングHaskell (第二章の練習問題)

in

プログラミングHaskell 第二章練習問題。(Hugsを用いて実行はghc v6.10.4です)このあたりはまだ、余裕があります。(^^)

2.6 (1) 括弧をつけよ

-- 2^3*4
a=(2^3)*4
-- 2*3+4*5
b=(2*3)+(4*5)
-- 2+3*4^5
c=2+(3*(4^5))

2.6 (2) Hugsを用いて実行せよ。

*Main>: a
32
*Main> b
26
*Main> c
3074
*Main> d

2.6 (3) エラーを修正しHugsで実行せよ

プログラミングHaskell (翻訳版)で再び (第一章の練習問題)

in

しばらく頭を冷やしている間に立て続けにProgramming in HaskellとRreak World Haskellの翻訳がでて大忙し。Programming in Haskellが翻訳中なのは知っていましたが山本さんとうとうですねー。お疲れ様。ということで、邦訳でもう一度丁寧に読み返しはじめました。

祝! Haskellバージンスクリプトを書いた

in

テキストを読んでいるだけだとどうしてもダレてくるので思い切ってコードを書いてみました。お題は以下のようにデータベースから抽出したセミコロンで区切られた数値データを

30,773;50,838,846;7,230,463
1,637;1,410,874;288,999
30,218;39,266,091;13,714,126
23,434;53,026,153;6,621,278
6,181;2,781,656;850,041

桁数を揃えたレポートとして出力するスクリプトです。

解決はしたけれど...納得にはまだまだ遠い! だけど、先に進むよ。

in

昨日(前エントリ)の続き。いろいろ試した結果

p = item Main.>>= \x ->
    item Main.>>= \y ->
    item Main.>>= \z ->
    Main.return (x,z)

で、いけました。「Programming in Haskell]Chapter 8.4(p77)には、

p1 >>= \v1 ->
p2 >>= \v2 ->
:
pn >>= \vn ->
return (f v1 v2 .. vn)

p = do v1 <- p1
       v2 <- p2
       :
       vn <- pn
       return (f v1 v2 .. vn)

は同等だよって書いてあるのでいいとは思うのですが、同じならなんでdo式を使うとエラーになるんだ?と考えてみると、昨日は関係ないかとも思ったのですが、やっぱり怪しいのは(>>=)。

Programming in Haskell Chapter 8 で躓く

in

どうにかこうにか読み進めてきた「Programing in Haskell」Chapter8 8.4 Sequencingで躓いてます。文字列の1番目と3番目の文字でペアを作成するというサンプルなんですがうまくいきません。実行例は次の通りです。

> parse p "abcdef"
[(('a','c'),"def")]

本書で、示されている定義は(前段からの続きも含めて)次のようになっています。

List comprehensionsとrubyのeach

in

すっかり堅くなった頭をほぐしながらですが、Haskell勉強中です。

今日、リスト内包表記のサンプルとして取り上げられることの多いqsortのコードを眺めていて気がついたのですが、

qsort[] = []
qsort(x:xs) = qsort smaller ++ [x] ++ qsprt lerger
              where
                smaller = [ a | a <- xs, a<=x]
                larger = [ b | b <- xs, b> x]

リスト内包記法(smallerとlargerの)部分って、どこかで見たことあると思ったらこれってrubyの"each { | a |”にそっくりなんですよね。

xs = [1,2,3,4,5]
xs.each { |a|
  print a if a <= x
}

Haskellの記法は

A ∩ B = { x | x ∈ A and x ∈ B }

みたいな、とおお〜い記憶の彼方にある数学の集合演算の記法をもとににしているようで、rubyのeach構文もきっとこれをもとにしたのだろうなということが今日わかりました(もちろん、たぶんですが....)

Haskellの構文は数学の素養豊な人にはHaskellの記法もスンナリ頭に入るのかもしれませんが、僕の場合だとrubyの構文のほうがやっぱりわかりやすい気がします。今日の今日まで、なぜeachは"each { | x |"という記法なのか?などということは考えたこともなかったので、"あるプログラミング言語の構文がなぜこのような記法となっているのか?”ということに思い至っただけでもHaskellの勉強を始めた意義があるってモン
ですね。それにしてもHaskellの勉強は遅々としてすすみません!(^^ゞ

コンテンツの配信