読者です 読者をやめる 読者になる 読者になる

Haskellでポーカーを作ろう 第二回についてメモ

tune.hateblo.jp

Haskellには、部品同士を繋げるための糊が呆れるほど沢山ありますので、 とにかく、必要だと解っている部分は作ってしまうのがポイント

newtype宣言

newtype Hand = Hand { fromHand :: [Card] } deriving (Show, Eq, Ord)

type宣言をすることで既存の型に別名をつけることができる.型に別名を付けることでわかりやすくなるが,型そのものは同じなので別の型でも値を与えることができてしまうことがある.

newtype K = K Double
newtype C = C Double

K,C共にベースとなる型はDoubleだがこれらは全く別の型になったためインターフェースとして安全になる.

モジュールの定義とエクスポート

module Hands (Hand, toHand, fromHand) where

特定のエンティティだけをエクスポートしたい場合はそれらを括弧の中に記述する.そのことをエクスポートリストと呼ぶ

コンストラクタとデータコンストラクタ

data Hand = Hand { fromHand :: [Card] }

これは新しい型と,その型の値を作る方法と,型の値がもつフィールドの型を宣言している.

dataの次のHandが新しい型の名前.型コンストラクタと呼ぶ.型コンストラクタはアルファベット大文字で始まる識別子でなければならない.

=の右側のHandはHand型のデータコンストラクタ.これも大文字で始まる識別子でなければならない.データコンストラクタは関連付けられた型の値を作成するときに使う.型コンストラクタとデータコンストラクタ名前空間が別れているので,両方に同じ名前を使うことができる.

fromHand :: [Card]はフィールドラベルを使って型を指定している.fromHandフィールドの型を[Card]としている.

追記

これで実際に新しく定義した型を見てみたところ

data A = B { c :: Int, d :: String }

$:t B
=>B :: Int -> String -> A

$:t c
=>c :: A -> Int

$:t d
=>d :: A -> String

$let b = B {c = 1, d = "hoge"}
$:t b
=> A

$:t c b
=> 1

このようになりました. データコンストラクタにフィールド値の各値を与えると新しく定義した型の値のコンストラクタをなることを確認できました.またフィールド名はコンストラクトされた値から束縛された値を取り出す関数になっていることを確認しました.

フィールの役割をやっとイメージできるようになりました.

自分の中で理解できていない部分は元記事の

fromHand :: Hand -> [Card]

の部分.fromHandフィールドが[Card]型を返すのはいいのだけど,引数としてHand型を取る部分がよく分かっていない.

data A = B { C :: String, D :: Int}

上記のような型を考えたときに,フィールドの型は

C :: B -> String
D :: B -> Int

という認識でよいのだろうか...?データコンストラクタのことを理解できていない...

まず欲しい関数の型を書くことで、 どのような型を定義する必要があるのか、整理する事ができるのです

所感

こういった解説記事めっちゃありがたい.ただ僕のHaskell力が低いのでシュッと理解できない...本読みながら読み進めようと思います

@its_out_of_tuneさん,ありがとうございました〜

参考文献

ふつうのHaskellプログラミング ふつうのプログラマのための関数型言語入門

ふつうのHaskellプログラミング ふつうのプログラマのための関数型言語入門