Skip to content

Instantly share code, notes, and snippets.

@oyakata
Created August 31, 2011 16:23
Show Gist options
  • Save oyakata/1183941 to your computer and use it in GitHub Desktop.
Save oyakata/1183941 to your computer and use it in GitHub Desktop.
人生初のHaskell -- ついでにユニットテストも書いてみた

Haskell

関数の宣言と定義

関数は引数と戻り値の型を予め宣言した上で定義することができる。

(宣言せずにいきなり定義を書いても型推論が働いて大丈夫らしい)

関数の宣言は以下の構文で行う。

<関数の名前> :: <引数の型> -> <戻り値の型>

foo :: Int -> Int

モジュール

http://www.shido.info/hs/haskell11.html

このURLにある通り、whereを使ってモジュールを定義するらしい。 インポートするときはimportで行う。

また、外部のモジュールから参照可能な関数を制限したり、インポートの際に対象を絞って行う方法などがあるがこれらは追々覚えればよいので今は適当。

任意の型を定義するにはdataをつかう

構文は以下の通り。

data <型の名前> = <構成子> | <構成子> | ...

これを使うと任意の型を定義することができる。

型推論について

細かいことを調べきっていないのだが、

型の推論はどうやら、

  • 引数の数が同じである。
  • 引数の型が同じである(あくまでも想像。コードで試していない)。
  • 引数の型と数が同じ場合は左辺に来る方(=式の中で先の位置にあるもの)が優先される。

というルールがあるみたいだ。

最初、Engineer型にはBeriefとBusiness型だけ定義していたのだが、

「あれ?これってBeriefと同じ型と引数の数の型を増やすとどうなるの?」

と疑問に思い試してみた次第。

結果はテストケースの通り、先にMoneyを使うとMoneyと推論され、Beriefを使うとBeriefと推論される。

(つまり信頼よりお金を先にすると結果はマイナスになってしまうのである。)

ユニットテストの書き方

以下のブログ記事を参考にした。

省略記法があるようだがこちらは読みにくいので使う気が起こらない。

また、TestLabelとか、assertEqualの第1引数のラベル文字列はいちいち渡さなければならないのだろうか?

というか、Javaやpythonのunittestのように、クラスを書くだけで実行可能なテストケースを作ることはできないものか。

見よう見まねで書いたこのテストケースは色々書いていて面倒くさいなと思った。

この辺は今後の課題だ。

感想

『プログラミングHaskell』というHaskellの薄い本を購入するまではぐぐっても利用し易い情報が見つからずどうなることかと思ったが、この本とwikipediaを使って何とか通るプログラムを書くことに成功してほっとしている。

module Hello where
data Engineer = Berief Int | Business Engineer Engineer | Money Int
team_work :: Int -> Int
team_work b = if b >= 0 then b else 1
haruo :: Engineer -> Int
haruo (Berief b) = team_work(b)
haruo (Business en1 en2) = haruo(en1) * haruo(en2) * 10
haruo (Money m) = m * (-1)
module TestHello where
import Test.HUnit
import Hello
test_single_berief =
TestCase(assertEqual "Test a single Berief value."
(haruo(Berief 10)) 10
)
test_single_money =
TestCase(assertEqual "Test a single Money value."
(haruo(Money 100)) (-100)
)
test_business =
TestCase(assertEqual "Test Business."
(haruo(Business (Berief 10) (Berief 10))) 1000
)
test_nested_business_with_berief =
TestCase(assertEqual "Test nested Business."
(haruo(
Business (Berief 10) (Business (Berief(-1)) (Berief 1))
)) (1000)
)
test_nested_business_with_money =
TestCase(assertEqual "Test nested Business. But, Money prior to."
(haruo(
Business (Money 10) (Business (Berief(-1)) (Berief 1))
)) (-1000)
)
main =
runTestTT (test [
TestLabel "test1" test_single_berief,
TestLabel "test2" test_single_money,
TestLabel "test3" test_business,
TestLabel "test4" test_nested_business_with_berief,
TestLabel "test5" test_nested_business_with_money
])
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment