Windowsで、Haskellを勉強してみてます。と言っても、一日、二日です。全然理解してません。
逐次実行型のプログラミング言語しか知らない視点で、Haskellをいじってみようというページです。最初はひたすら関数型っぽくない逐次実行型言語としてHaskellを使う書き方をしていきたいと思います。
Haskellは関数型言語と呼ばれる種類のプログラミング言語です。 なにやら遅延評価というのがあり特徴になっているようです。再帰末尾の最適化とか、マクロってのも使えるみたいです。関数型言語というと、Lispがありますが、カッコの嵐になるので苦痛です。Haskellはその辺カッコの嵐に悩まされることなくプログラムすることができます。
まずは、インタプリタを拾ってきましょう。Hugs98というものがあります。
ここから、Downloading、hugs98-Nov2003-2.msi をダウンロードしてきました。 これを実行すれば、インストールできます。
デフォルトだと、
C:\Program Files\Hugs98
に実行ファイルがインストールされますので、環境変数のPATHにC:\Program Files\Hugs98を追加しましょう。
>hugs
と入力して、
__ __ __ __ ____ ___ _________________________________________ || || || || || || ||__ Hugs 98: Based on the Haskell 98 standard ||___|| ||__|| ||__|| __|| Copyright (c) 1994-2003 ||---|| ___|| World Wide Web: http://haskell.org/hugs || || Report bugs to: hugs-bugs@haskell.org || || Version: Nov 2003 _________________________________________ Haskell 98 mode: Restart with command line option -98 to enable extensions Type :? for help Prelude>
な画面が出ればインストール成功です。
Prelude>:quit
と入力して抜けましょう。
では、HelloWorld?を作ります。関数型言語を学ぶ場合に、HelloWorld?から入るのは邪道なのかもしれないですが、逐次実行型言語しか知らない人にはなじみ深いので。
hello.hs
module Main (main) where main = putStr "Hello World !!\n"
>runhugs hello.hs
として、実行します。
Hello World !!
と表示されれば成功です。
このソースの意味は
モジュールMainで外部プログラムからはmain関数を参照できます。モジュールの中身は、、、 main関数は"Hello World !!改行"を画面に出力します。
といったかんじだと思います。
コンパイラがあるらしいので、コンパイルもしてみてしまいましょう。
上のサイトから、Windows版のコンパイラのバイナリを拾ってきてインストールします。
デフォルトでは、
C:\ghc\ghc-6.2.2\bin
に実行ファイルがあるので、パスを通します。
>ghc -o hello hello.hs
とすれば、hello.exeが出来上がるはずです。
>hello
と入力して、
Hello World!!
と表示されれば成功です。
HSDLというライブラリがtanakhさんから公開されています。テトリスが動いています。
なんか、ゲームも作れるいうと安心です。それだけです。ってのはあれなので、逐次実行型のプログラムになれている人は、ソースが参考になるかなと思います。
ここを参考に分からなかったところを、分かるようにして書いていきます。
ここから、ダウンロードします。
Windowsな人なら解凍して適当なディレクトリに展開します。
>wxhaskell-register.bat
でインストールできます。
>wxhaskell-unregister.bat
でアンインストールできるので、ディレクトリの位置は変更できるます。悩まずインストールしましょう。私は最初、ここで止まってしまった。大丈夫かなと。
helloworld.hs
module Main where import Graphics.UI.WX main = start mainFrame mainFrame = do f <- frameFixed [text := "Hello World"] p <- panel f [] set f [layout := minsize (sz 300 300) $ widget p]
コンパイルはこう。wxパッケージを使うと言わないといけないみたい。ちゃんとホームページに書いてあるのだけど、端折って悩んでしまった。
ghc -package wx -o helloworld helloworld.hs
こんどは、こんなエラー
mismatched interface file versions: expected 6022, found 6021
これは、hiファイルのバージョン違いってことらしい。ghcが 6.2.2でwxHaskellが6.2.1で違うと。ghcを6.2.1にバージョンダウンしよう。パスも書き換えて、、、。
で、しばらく待つとhelloworld.exeができます。
helloworld
これで、実行できました。
これで、表示されればOKです。
とりあえず、簡単なプログラムで構文を覚えていきましょう。
まずは、文字列表示です。
module Main(main) where main = putStr "Hello World !!\n"
module Main; void main() printf("Hello World!!\n");
dはコンパイルできません。
do構文はD言語でいうところの{}です。式の集まりを表現します。 doは、doが始まる式よりネストが下がっている間、効力があります。変な文章だな。
module Main(main) where main = do putStr "Hello World!!\n"
module Main; void main(){ printf("Hello World!!\n"); }
module Main(main) where main = do putStr "1\n" putStr "2\n"
module Main; void main(){ printf("1\n"); printf("2\n"); }
複数行コメントと、1ラインコメントがあります。
{- コメント -} -- 1行コメント module Main(main) where main = do putStr "comment\n"
/* コメント */ // 1行コメント module Main; void main(){ printf("comment\n"); }
module Main(main) where main = do putStr "Name?\n" c <- getLine putStr "hello " putStr c putStr ".\n"
module Main; void main(){ printf("Name?\n"); char[] c = stdin.readLine(); printf("hello ",c); printf("%.*s",c); printf(".\n"); }
{-文字列の結合-} module Main(main) where main = do putStr a ++ "def\n" where a = "abc"
mainも関数なわけですが、main以外の関数を定義してみます。
-- 返り値なし関数 module Main(main) where func = do putStr "func" main = do func
-- 引数付き、返り値なし関数 module Main(main) where func a = do putStr a ++ "\n" main = do func "abc"
-- 処理なし関数 module Main(main) where a = "abc" main = do putStr (a ++ "\n")
-- ブロック無し引数付き関数 module Main(main) where func a = (a ++ "abc") main = do putStr (func "abc")
-- ブロックあり関数 module Main(main) where func = do "abc" -- 最後に評価された値が返される。 main = do putStr func
-- ブロックあり関数 module Main(main) where func = do a -- 最後に評価された値が返される。 where a = "123" main = do putStr func
-- ブロックあり引数あり関数 module Main(main) where func a = do (a ++ "abc") main = do putStr (func "abc")
-- ブロックあり複数引数あり関数 module Main(main) where func a b = do (a ++ b) main = do putStr (func "abc" "def")
-- ブロックありタプル引数あり関数(これは引数1つの関数) module Main(main) where func (a, b) = do (a ++ b) func3 (a,b,c) = do (a ++ b ++ c) main = do putStr (func("abc","def") ++ "\n") putStr (func3("abc","def","ghi") ++ "\n")
module Main(main) where func = do ["1","2","3"] main = do let [x,y,z] = func putStr ( x ++ y ++ z ++ "\n")
c言語などのif文にあたる構文です。式っていうみたいですね。
module Main(main) where main = do a <- getLine if a == "1" then do putStr "a == 1\n" else do putStr "a != 1\n"
module Main(main) where main = do a <- getLine if a == "1" then do putStr "a == 1\n" else do putStr "a != 1\n"
module Main(main) where main = do a <- getLine if a == "1" then putStr "a == 1\n" else putStr "a != 1\n"
c言語などのswitch文にあたる構文です。式っていうみたいですね。
module Main(main) where main = do a <- getLine case a of "1" -> putStr "1da" "2" -> putStr "2da" _ -> putStr "1 demo 2 demo nai."
module Main(main) where main = do a <- getLine case a of "1" -> do putStr "1da" "2" -> do putStr "2da" _ -> do putStr "1 demo 2 demo nai."
if式、case式の別な書き方です。パターン照合の一種らしい。
トップレベルでしか書けません。
module Main(main) where test a | a == "1" = do putStr "a == 1\n" | not (a == "1") = do putStr "a != 1\n" main = do a <- getLine test a
doとっぱらうとこうなります。まとまりすぎてて、暗号を読んでいるよう。
module Main(main) where test a | a == "1" = putStr "a == 1\n" | not (a == "1") = putStr "a != 1\n" main = do a <- getLine test a
!=ではなくて、/=なんですね。
module Main(main) where test a | a == "1" = putStr "a == 1\n" | a /= "1" = putStr "a != 1\n" main = do a <- getLine test a
otherwiseと書くと、それ以外ってことのようです。
module Main(main) where test a | a == "1" = putStr "a == 1\n" | otherwise = putStr "a != 1\n" main = do a <- getLine test a
関数内の関数が定義できます。 ローカル変数の初期化のような感じにも使えます。
module Main(main) where main = do putStr a where a = "1"
module Main(main) where main = do put where a = "1" put = do putStr "put\n"
モジュール自体もwhereクロージャになってるので、こう書けると。
module Main(main) where a = "1" put = putStr "put\n" main = do put
代入ではないのですが、代入のように使えます。
本当は、式をまとめるってだけの役割で、遅延評価されるようです。
module Main(main) where main = do x <- getLine let a = x putStr a
module Main(main) where main = do let a = x putStr a where x = "123"
module Main(main) where main = do let a = "abc" putStr a
module Main(main) where main = do let a = "abc" let b = "def" let c = a ++ b putStr c
module Main(main) where main = do let a = "abc" let b = "def" let a = a ++ b putStr a
これは、うまくいきません。エラーにもならないのは謎です。 ghc(コンパイラ)を通すと、Fail: <<loop>>とでます。