Haskellメモ


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?を作ります。関数型言語を学ぶ場合に、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さんから公開されています。テトリスが動いています。

なんか、ゲームも作れるいうと安心です。それだけです。ってのはあれなので、逐次実行型のプログラムになれている人は、ソースが参考になるかなと思います。

GUIライブラリを使う

ここを参考に分からなかったところを、分かるようにして書いていきます。

wxHaskellのインストール

ここから、ダウンロードします。

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です。

構文

とりあえず、簡単なプログラムで構文を覚えていきましょう。

HelloWorld?

まずは、文字列表示です。

  • hello.hs
	module Main(main) where
	main = putStr "Hello World !!\n"
  • hello.d
	module Main;
	void main() printf("Hello World!!\n");

dはコンパイルできません。


do構文

do構文はD言語でいうところの{}です。式の集まりを表現します。 doは、doが始まる式よりネストが下がっている間、効力があります。変な文章だな。

  • do.hs
	module Main(main) where
	main = do
	  putStr "Hello World!!\n"
  • do.d
	module Main;
	void main(){
		printf("Hello World!!\n");
	}
  • do2.hs
	module Main(main) where
	main = do
	  putStr "1\n"
	  putStr "2\n"
  • do2.d
	module Main;
	void main(){
		printf("1\n");
		printf("2\n");
	}

コメント

複数行コメントと、1ラインコメントがあります。

  • comment.hs
	{- コメント -}
	-- 1行コメント
	module Main(main) where
	main = do
		putStr "comment\n"
  • comment.d
	/* コメント */
	// 1行コメント
	module Main;
	void main(){
		printf("comment\n");
	}

標準入力

  • stdin.hs
	module Main(main) where
	main = do
		putStr "Name?\n"
		c <- getLine
		putStr "hello "
		putStr c
		putStr ".\n"
  • stdin.d
	module Main;
	void main(){
		printf("Name?\n");
		char[] c = stdin.readLine();
		printf("hello ",c);
		printf("%.*s",c);
		printf(".\n");
	}

文字列

  • string.hs
    	{-文字列の結合-}
    	module Main(main) where
    	main = do
    		putStr a ++ "def\n"
    		where
    			a = "abc"

関数

mainも関数なわけですが、main以外の関数を定義してみます。

  • function.hs
	-- 返り値なし関数
	module Main(main) where
	func = do
		putStr "func"
	main = do
		func
  • function2.hs
	-- 引数付き、返り値なし関数
	module Main(main) where
	func a = do
		putStr a ++ "\n"
	main = do
		func "abc"
  • function3.hs
	-- 処理なし関数
	module Main(main) where
	a = "abc"
	main = do
		putStr (a ++ "\n")
  • function4.hs
	-- ブロック無し引数付き関数
	module Main(main) where
	func a = (a ++ "abc")
	main = do
		putStr (func "abc")
  • function5.hs
	-- ブロックあり関数
	module Main(main) where
	func = do
		"abc" -- 最後に評価された値が返される。
	main = do
		putStr func
  • function6.hs
	-- ブロックあり関数
	module Main(main) where
	func = do
		a -- 最後に評価された値が返される。
		where
			a = "123"
	main = do
		putStr func
  • function7.hs
	-- ブロックあり引数あり関数
	module Main(main) where
	func a = do
		(a ++ "abc")
	main = do
		putStr (func "abc")
  • function8.hs
	-- ブロックあり複数引数あり関数
	module Main(main) where
	func a b = do
		(a ++ b)
	main = do
		putStr (func "abc" "def")
  • function9.hs
	-- ブロックありタプル引数あり関数(これは引数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")
  • function10.hs
	module Main(main) where
	func = do
		["1","2","3"]
	main = do
		let [x,y,z] = func
		putStr ( x ++ y ++ z ++ "\n")

if式

c言語などのif文にあたる構文です。式っていうみたいですね。

  • if.hs
	module Main(main) where
	main = do
		a <- getLine
		if a == "1"
			then do
				putStr "a == 1\n"
			else do
				putStr "a != 1\n"
  • if2.hs
	module Main(main) where
	main = do
		a <- getLine
		if a == "1" then do
				putStr "a == 1\n"
			else do
				putStr "a != 1\n"
  • if3.hs
	module Main(main) where
	main = do
		a <- getLine
		if a == "1" then putStr "a == 1\n" else putStr "a != 1\n"

case式

c言語などのswitch文にあたる構文です。式っていうみたいですね。

  • case.hs
	module Main(main) where
	main = do
		a <- getLine
		case a of
			"1" -> putStr "1da"
			"2" -> putStr "2da"
			_ -> putStr "1 demo 2 demo nai."
  • case2.hs
	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式の別な書き方です。パターン照合の一種らしい。

トップレベルでしか書けません。

  • block.hs
	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
  • block2.hs

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
  • block3.hs

!=ではなくて、/=なんですね。

	module Main(main) where
	test a | a == "1" = putStr "a == 1\n"
	       | a /= "1" = putStr "a != 1\n"
	main = do
		a <- getLine
		test a
  • block4.hs

otherwiseと書くと、それ以外ってことのようです。

	module Main(main) where
	test a | a == "1"  = putStr "a == 1\n"
	       | otherwise = putStr "a != 1\n"
	main = do
		a <- getLine
		test a

whereクロージャ

関数内の関数が定義できます。 ローカル変数の初期化のような感じにも使えます。

  • where.hs
	module Main(main) where
	main = do
		putStr a
		where
			a = "1"
  • where2.hs
	module Main(main) where
	main = do
		put
		where
			a = "1"
			put = do
				putStr "put\n"
  • where3.hs

モジュール自体もwhereクロージャになってるので、こう書けると。

	module Main(main) where
	a = "1"
	put = putStr "put\n"
	main = do
		put

let式

代入ではないのですが、代入のように使えます。

本当は、式をまとめるってだけの役割で、遅延評価されるようです。

  • let.hs
	module Main(main) where
	main = do
		x <- getLine
		let a = x
		putStr a
  • let2.hs
	module Main(main) where
	main = do
		let a = x
		putStr a
		where
			x = "123"
  • let3.hs
	module Main(main) where
	main = do
		let a = "abc"
		putStr a
  • let4.hs
	module Main(main) where
	main = do
		let a = "abc"
		let b = "def"
		let c = a ++ b
		putStr c
  • let5.hs
	module Main(main) where
	main = do
		let a = "abc"
		let b = "def"
		let a = a ++ b
		putStr a

これは、うまくいきません。エラーにもならないのは謎です。 ghc(コンパイラ)を通すと、Fail: <<loop>>とでます。


リンク

*MenuBar

人気の10件

  • counter: 15274
  • today: 1
  • yesterday: 0
  • online: 1