私はこれが私の宿題であることを認めます。しかし、一生懸命取り組んだ後、本当に良い解決策を見つけることができませんでした.
これを達成するには、次のような愚かな方法があるかもしれません。
myHead (x:[]) = x
myHead (x:y:xs) = fst (x, y)
でもそれは先生が望んでいることではないと思います。
ところで、エラー処理は必要ありません。
前もって感謝します!
私はこれが私の宿題であることを認めます。しかし、一生懸命取り組んだ後、本当に良い解決策を見つけることができませんでした.
これを達成するには、次のような愚かな方法があるかもしれません。
myHead (x:[]) = x
myHead (x:y:xs) = fst (x, y)
でもそれは先生が望んでいることではないと思います。
ところで、エラー処理は必要ありません。
前もって感謝します!
uncurried cons の逆である "uncons" と呼ばれるプレリュードにない非常に自然な関数があります。
cons :: a -> [a] -> [a]
uncurry cons :: (a, [a]) -> [a]
uncons :: [a] -> (a, [a])
uncons (x:xs) = (x, xs)
これを使用して head を次のように実装できます
head = fst . uncons
なぜuncons
自然なのですか?
リストは、2 つのコンストラクター関数を使用して定義されたデータ型と考えることができます。
nil :: [a]
nil = []
cons :: (a, [a]) -> [a]
cons (a,as) = a:as
関数によって分解されるデータ型と考えることもできます
destruct :: [a] -> Maybe (a, [a])
destruct [] = Nothing
destruct (a:as) = Just (a, as)
それらがリストタイプに決定的に結び付けられている理由を説明するのはこの答えをはるかに超えていますが、それを見る1つの方法は、定義しようとすることです
nil :: f a
cons :: (a, f a) -> f a
また
destruct :: f a -> Maybe (a, f a)
他のコンテナ タイプの場合f
。それらはすべて、リストと非常に密接な関係にあることがわかります。
uncons
の定義の 2 番目のケースでは、ほぼ既に確認できますが、途中でdestruct
がありJust
ます。これは、空のリストで定義されていないおよび とuncons
組み合わせたほうがよいhead
tail
head [] = error "Prelude.head"
そのため、以前の回答を無限ストリームで機能するように調整できます。ここで、無限ストリームは 1 つの関数によって構築されると考えることができます。
data Stream a = Next a (Stream a)
cons :: (a, Stream a) -> Stream a
cons (a, as) = Next a as
1つの関数によって破壊されます
uncons :: Stream a -> (a, Stream a)
uncons (Next a as) = (a, as)
-- a. k. a.
uncons stream = (head stream, tail stream)
2つは互いに逆です。
から戻りタプルの最初の要素を取得することhead
で、 s を取得できます。Stream
uncons
head = fst . uncons
それが のhead
モデルPrelude
なので、リストが無限の流れであるかのように見せかけ、そのように head を定義できます。
uncons :: [a] -> (a, [a])
uncons (a:as) = (a, as)
-- a. k. a.
uncons list = (head list, tail list)
head = fst . uncons