generated at
head関数のいくつかの定義
1つの配列を引数にとって、その先頭要素を返す関数 head の定義


不正な値は実行時エラーを生じさせる
Preludeのhead関数の定義これ ref
型安全でない
部分関数になっている
型が嘘をついているmrsekut
実行時エラーが生じうる
定義.hs
head :: [a] -> a head (x:_) = x head [] = error "empty list"
使用.hs
let xs = head [] -- no type error, runtime error



不正な値はダミー値で表現する
空配列を適用した時は、 NULL を返す
nullの表す意味が多義なので、その結果が何を意味するのかが曖昧になる
例えば以下はいずれもNILを返すが、その違いを値から読み取れない
lisp
(car '()) ; 不正な入力なのでNILを返す (car '(() (1 2 3) (4 5 6)))) ; 先頭要素が空リストなのでNILを返す (car '(NIL (1 2 3) (4 5 6)))) ; 先頭要素がNILなのでNILを返す
これらを区別したい時、追加でハックが必要になる
e.g. Lispのcar関数
使用.lisp
(car '()) NIL
e.g. Goの Front() ref
定義.go
func (l *List) Front() *Element { if l.len == 0 { return nil } return l.root.next }
Haskellでやるなら、ダミー値を要求するとか
hs
headOr :: a -> [a] -> a headOr def (x:xs) = x headOr def [] = def



返り値を Maybe にする
定義.hs
head :: [a] -> Maybe a head [] = Nothing head (x:_) = Just x
全域関数である
型に嘘はない
実行時エラーは起きない
この関数の利用者は、 Maybe のパターンマッチしてhandlingする必要がある
明らかに Just が返ってくるような文脈でもhandlingが必要になる
ここで、 fromJust を使えばhandlingせずに済むが、
しかし、そうすると結局型の嘘が生じるため、実行時エラーの危険性が再燃する
関数の提供者は楽かもしれないが、利用者は面倒
この例ではそこまで問題ではないが、上の NULL と同様の問題も生じている
Nothing の多義性
例えばCustom Preludeのrioはこの定義を提供している ref



そもそも空配列を適用できないようにする
引数の型をNonEmptyにする
型に嘘はない
全域関数である
Maybe の時に生じたhandlingも不要
定義.hs
head :: NonEmpty a -> a head (x :| _) = x
短所は、 length など、通常の List の関数と同様の関数を再定義する必要があること
例えばCustom Preludeのreludeはこの定義を提供している ref
NonEmpty の定義から Maybe の定義を作るのは容易
逆は難しい
hs
head' :: [a] -> Maybe a head' = fmap head . nonEmpty


hs
rev_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
う〜ん、これ言うほど楽なのか?mrsekut
gdpHead 内で使っている head はPreludeのものなので、 NonEmpty の時のように [a] と同じ関数を再定義する必要がない





篩型を用いた定義
with refined
hs
head :: SizeGreaterThan 0 a -> a head = Prelude.head . unrefine