head関数のいくつかの定義
1つの配列を引数にとって、その先頭要素を返す関数 head
の定義
不正な値は実行時エラーを生じさせる
型安全でない
部分関数になっている
型が嘘をついている

実行時エラーが生じうる
定義.hs head :: [a] -> a
head (x:_) = x
head [] = error "empty list"
使用.hslet xs = head [] -- no type error, runtime error
不正な値はダミー値で表現する
空配列を適用した時は、 NULL
を返す
例えば以下はいずれもNILを返すが、その違いを値から読み取れない
lisp(car '()) ; 不正な入力なのでNILを返す
(car '(() (1 2 3) (4 5 6)))) ; 先頭要素が空リストなのでNILを返す
(car '(NIL (1 2 3) (4 5 6)))) ; 先頭要素がNILなのでNILを返す
これらを区別したい時、追加でハックが必要になる
定義.gofunc (l *List) Front() *Element {
if l.len == 0 {
return nil
}
return l.root.next
}
Haskellでやるなら、ダミー値を要求するとか
hsheadOr :: a -> [a] -> a
headOr def (x:xs) = x
headOr def [] = def
返り値を Maybe
にする
定義.hshead :: [a] -> Maybe a
head [] = Nothing
head (x:_) = Just x
全域関数である
型に嘘はない
実行時エラーは起きない
この関数の利用者は、 Maybe
のパターンマッチしてhandlingする必要がある
明らかに Just
が返ってくるような文脈でもhandlingが必要になる
ここで、 fromJust
を使えばhandlingせずに済むが、
しかし、そうすると結局型の嘘が生じるため、実行時エラーの危険性が再燃する
関数の提供者は楽かもしれないが、利用者は面倒
この例ではそこまで問題ではないが、上の NULL
と同様の問題も生じている
Nothing
の多義性
例えばCustom Preludeの
rioはこの定義を提供している
ref
そもそも空配列を適用できないようにする
型に嘘はない
全域関数である
Maybe
の時に生じたhandlingも不要
定義.hshead :: NonEmpty a -> a
head (x :| _) = x
短所は、 length
など、通常の List
の関数と同様の関数を再定義する必要があること
NonEmpty
の定義から Maybe
の定義を作るのは容易
逆は難しい
hshead' :: [a] -> Maybe a
head' = fmap head . nonEmpty
hsrev_cons :: Proof (IsCons xs) -> Proof (IsCons (Rev xs))
rev_cons = axiom
gdpHead :: ([a] ~~ xs ::: IsCons xs) -> a
gdpHead xs = head (the xs)
-- 使用
gdpEndpts :: IO (Int, Int)
gdpEndpts = do
putStrLn "Enter a non-empty list of integers:"
xs <- readLn
name xs $ \xs-> case classify xs of
IsCons proof ->
return (gdpHead (xs ...proof),
gdpHead (gdpRev xs ...rev_cons proof))
IsNil proof -> gdpEndpts
う〜ん、これ言うほど楽なのか?

gdpHead
内で使っている head
はPreludeのものなので、 NonEmpty
の時のように [a]
と同じ関数を再定義する必要がない
篩型を用いた定義
hshead :: SizeGreaterThan 0 a -> a
head = Prelude.head . unrefine