如何使用fst函数实现head函数

时间:2013-11-04 12:07:08

标签: haskell

我承认这是我的功课。但是在努力工作之后,我真的找不到一个好的解决方案。

可能有一些愚蠢的方法可以实现这一点,例如:

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

但我认为这不是老师想要的。
顺便说一下,不需要进行错误处理。

提前致谢!

3 个答案:

答案 0 :(得分:4)

有一种非常自然的功能,不在前言中称为“uncons”,这是未经证实的缺点的反面。

cons :: a -> [a] -> [a]
uncurry cons :: (a, [a]) -> [a]

uncons :: [a] -> (a, [a])
uncons (x:xs) = (x, xs)

您可以使用它来实现头部

head = fst . uncons

为什么uncons自然?

您可以将列表视为通过使用两个构造函数定义的数据类型

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)

解释为什么那些明确地与列表类型相关联,这远远超出了这个答案,但是看待它的一种方法是尝试定义

nil      :: f a
cons     :: (a, f a) -> f a

destruct :: f a -> Maybe (a, f a)

对于任何其他容器类型f。你会发现他们都与列表关系密切。

uncons的定义的第二种情况下,您几乎已经可以看到destruct了,但路上有Justuncons最好与headtail配对,但未在空列表中定义

head [] = error "Prelude.head"

因此我们可以调整之前的答案,以便为无限流工作。在这里,我们可以将无限流视为由一个函数

构造
data Stream a = Next a (Stream a)

cons :: (a, Stream a) -> Stream a
cons (a, as) = Next a as

并由一个函数破坏

uncons :: Stream a -> (a, Stream a)
uncons (Next a as) = (a, as)

-- a. k. a.
uncons stream = (head stream, tail stream)
这两个人彼此相反。

现在,我们可以通过head

获取返回元组的第一个元素来获取Stream uncons
head = fst . uncons

这就是head中的Prelude模型,所以我们可以假装列表是无限流,并以这种方式定义头

uncons :: [a] -> (a, [a])
uncons (a:as) = (a, as)

-- a. k. a.
uncons list = (head list, tail list)

head = fst . uncons

答案 1 :(得分:2)

也许您希望写入自己的缺点列表类型,然后可能更有意义。虽然类型同义词不能递归,所以你最终使用非元组数据构造函数,使元组变得多余..它看起来像:

data List a = Nil | List (a, List a)
        deriving( Show )

head :: List a -> a
head (List c) = fst c

答案 2 :(得分:1)

就像在评论中已经说过的那样,这只是一个愚蠢的任务,你不会得到一些你称之为head的良好实现的东西。

对于这些要求,您的解决方案很好 - 作为唯一的更改我将(x:y:xs)替换为(x:y:_),因为根本不使用xs(这实际上会导致某些设置中的编译器警告)。事实上,您也可以使用y执行此操作:

myHead (x:_:_) = fst (x, undefined)

有些替代方案看起来可能不是相当所以useless use of fst,即不只是手工构建元组并立即再解构它:

myHead' [x] = x
myHead' xs = myHead' . fst $ splitAt 1 xs

myHead'' = foldr1 $ curry fst

myHead''' = fromJust . find ((==0) . fst) . zip [0..]

但你可以理所当然地说这些只是荒谬的。