結城浩のHaskell日記 RSSフィード

2006-05-30

filter関数 filter関数 - 結城浩のHaskell日記 を含むブックマーク

filter関数は指定した関数(これはBoolを返す述語)に合致する要素だけを集めたリストを返します。myfilterとして定義すると…。

myfilter :: (a -> Bool) -> [a] -> [a]
myfilter _ [] = []
myfilter f (x:xs) = if (f x) then (x:(myfilter f xs))
                             else (myfilter f xs)

実行結果です。isUpperが使えなかったので、Char.isUpperと書きました。import Charの代わりのつもり。

> ghci a.hs
   ___         ___ _
  / _ \ /\  /\/ __(_)
 / /_\// /_/ / /  | |      GHC Interactive, version 6.2.2, for Haskell 98.
/ /_\\/ __  / /___| |      http://www.haskell.org/ghc/
\____/\/ /_/\____/|_|      Type :? for help.

Loading package base ... linking ... done.
Compiling Main             ( a.hs, interpreted )
Ok, modules loaded: Main.
*Main> myfilter isUpper "HelloWorld"

<interactive>:1: Variable not in scope: `isUpper'
*Main> myfilter Char.isUpper "HelloWorld"
"HW"
*Main> myfilter Char.isDigit "He110W0r1d"
"11001"
*Main> :q
Leaving GHCi.

ところで、カッコはもっと少なくできるようですね。

myfilter :: (a -> Bool) -> [a] -> [a]
myfilter _ [] = []
myfilter f (x:xs) = if f x then x:myfilter f xs
                             else myfilter f xs

パターンのところの(x:xs)のカッコはとれないようですね。

次はp.92から。

tail関数 tail関数 - 結城浩のHaskell日記 を含むブックマーク

tail関数はcdrですね。いつものようにmytailを定義します。

mytail :: [a] -> [a]
mytail (x:xs) = xs

ghciを使って試します。コマンドラインの引数でファイルを指定すれば、ロードしてくれることを知りました。

> ghci a.hs
   ___         ___ _
  / _ \ /\  /\/ __(_)
 / /_\// /_/ / /  | |      GHC Interactive, version 6.2.2, for Haskell 98.
/ /_\\/ __  / /___| |      http://www.haskell.org/ghc/
\____/\/ /_/\____/|_|      Type :? for help.

Loading package base ... linking ... done.
Compiling Main             ( a.hs, interpreted )
Ok, modules loaded: Main.
*Main> mytail [1,2,3]
[2,3]
*Main> mytail "Hello"
"ello"
*Main> mytail []
*** Exception: a.hs:2: Non-exhaustive patterns in function mytail

*Main>

よし、それなら、次のようなa.batを作っておけば良いんですね。

ghci a.hs

ちなみに、ghci --helpでヘルプが出ます。

ユークリッドの互除法 ユークリッドの互除法 - 結城浩のHaskell日記 を含むブックマーク

二十代は模索のときブログを読んで、私もユークリッドの互除法をやってみる。

mygcd :: Integer -> Integer -> Integer
mygcd m 0 = m
mygcd m n = mygcd n (m `mod` n)

(このファイルをa.hsとします)。

実行結果です。

> ghci
   ___         ___ _
  / _ \ /\  /\/ __(_)
 / /_\// /_/ / /  | |      GHC Interactive, version 6.2.2, for Haskell 98.
/ /_\\/ __  / /___| |      http://www.haskell.org/ghc/
\____/\/ /_/\____/|_|      Type :? for help.

Loading package base ... linking ... done.
Prelude> :load a
Compiling Main             ( a.hs, interpreted )
Ok, modules loaded: Main.
*Main> mygcd 1071 1029
21
*Main> :q
Leaving GHCi.

ついでに、互除法のプロセスをペアのリストとして表現してみましょう。

euclidList :: Integer -> Integer -> [(Integer,Integer)]
euclidList m 0 = [(m,0)]
euclidList m n = (m,n):(euclidList n (m `mod` n))

さっそく実行。

Prelude> :l a
Compiling Main             ( a.hs, interpreted )
Ok, modules loaded: Main.
*Main> euclidList 1071 1029
[(1071,1029),(1029,42),(42,21),(21,0)]

head関数 head関数 - 結城浩のHaskell日記 を含むブックマーク

head関数はリストの最初の要素を得るようです。

Prelude> head [1,2,3]
1
Prelude> head ["Hello","World"]
"Hello"
Prelude> head []
*** Exception: Prelude.head: empty list
Prelude> head "Hello"
'H'

[]を与えると実行時のエラーになります。

これは簡単なので、自分でもmyhead関数を定義してみます。

myhead :: [a] -> a
myhead (x:xs) = x

ghciの:loadコマンドでこのスクリプトを読んで試してみよう。

Prelude> :l a.hs
Compiling Main             ( a.hs, interpreted )
Ok, modules loaded: Main.
*Main> myhead [1,2,3]
1
*Main> myhead []
*** Exception: a.hs:2: Non-exhaustive patterns in function myhead

*Main> myhead "Hello"
'H'

まだ(積極的な)エラーの出し方がわからない。上ではなすがままにエラーが出ている。

次はp.91から。

System.getArgsアクション System.getArgsアクション - 結城浩のHaskell日記 を含むブックマーク

System.getArgsアクションはコマンドライン引数をリストで得るアクションのようです。

import System

main = do cs <- getArgs
          print cs

コンパイルと実行。

>ghc a.hs -o a

>a
[]

>a 1 2 3
["1","2","3"]

>a hello world
["hello","world"]

>a "Hello, world" good nice
["Hello, world","good","nice"]

unwords関数 unwords関数 - 結城浩のHaskell日記 を含むブックマーク

unwords関数。いつものようにghciで動きをチェック。

Prelude> unwords ["a","b","c"]
"a b c"
Prelude> unwords ["Hello","world!"]
"Hello world!"
Prelude> unwords ["","",""]
"  "
Prelude> unwords["1","2"]
"1 2"

unwords関数はwords関数のほぼ逆だけれど、間に詰めるのは空白一つだから、完全に元に戻るわけではない。

Prelude> words "a b  c     d"
["a","b","c","d"]
Prelude> unwords (words "a b  c     d")
"a b c d"

練習のため、unwords関数と同じ動きをするmyunwords関数を定義してみよう。

myunwords :: [String] -> String
myunwords [] = ""
myunwords [x] = x
myunwords (x:xs) = x ++ " " ++ (myunwords xs)

うーん、いちおう動いたけれど。自信なし。

自作のmap関数 自作のmap関数 - 結城浩のHaskell日記 を含むブックマーク

自分で問題を作って解く練習。

問題:自作のmap関数を作る。名前はmymapにする。

main = do print $ mymap length ["abc","d","efg"]

mymap :: (a -> b) -> [a] -> [b]

mymap f [] = []
mymap f (x:xs) = ((f x):(mymap f xs))
  • 何だか思い出してきた。
  • ::で型を指定する。
  • (a -> b)はa型からb型へ写像する関数の型。
  • x:xsはcons。
  • 関数引数のパターンマッチ。
  • x:xsとしておいて、定義ではxを処理し、残りxsは再帰で処理。

昨日は電車に乗ったのでp.178まで一気に読んでしまいました。でもいちおう手で触りながら進むことにします。

次はp.82から。

nobsunnobsun2006/06/02 09:18foo (x:xs) = ...
bar (Just x) = ...
のように関数束縛の際に引数のpatternに括弧が必要なのは、
関数適用の結合力が強いのと、それが左結合性をもつことによります。
括弧がないと、
foo x : xs は (foo x) : xs のように
bar Just x は (bar Just) x のように解釈されてしまいます.
ただし,単独で出現するパターンの場合には括弧が省けます.
case baz of
[] -> ...
x:xs -> ...

nobsunnobsun2006/06/02 09:49list上の再帰関数は殆どの場合、Preludeにある高階関数を使って書けます。練習してみると楽しいですよ。