0

私はこれが私の宿題であることを認めます。しかし、一生懸命取り組んだ後、本当に良い解決策を見つけることができませんでした.

これを達成するには、次のような愚かな方法があるかもしれません。

myHead (x:[]) = x
myHead (x:y:xs) = fst (x, y)

でもそれは先生が望んでいることではないと思います。
ところで、エラー処理は必要ありません。

前もって感謝します!

4

3 に答える 3

4

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組み合わせたほうがよいheadtail

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 を取得できます。Streamuncons

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
于 2013-11-04T14:34:48.930 に答える