为什么Haskell [](列表)不是类型类?

时间:2017-03-01 01:48:39

标签: list haskell types interface typeclass

我正在编写一个Haskell函数,它以列表作为输入。也就是说,没有理由它不能成为队列或出队,或任何允许我访问其头部和#34;及其尾巴" (并检查它是否为空)。所以[a]输入类型似乎太具体了。但是AFAIK没有标准的库类型类可以捕获这个接口。当然,我可以将我的函数包装在Data.Foldable.toList中,并使其变形为可折叠的,但这看起来并不合适(惯用)。

为什么没有标准的列表类型类? (为什么Haskell中的"容器"类型类层次结构比我认为应该更少?)或者我错过了必要的东西?

2 个答案:

答案 0 :(得分:13)

给定的代数数据类型可以表示为其变形,一种称为Church encoding的变换。这意味着列表与foldr

同构
type List a = forall b. (a -> b -> b) -> b -> b

fromList :: [a] -> List a
fromList xs = \f z -> foldr f z xs

toList :: List a -> [a]
toList l = l (:) []

foldr也是Foldable的特征。您可以按foldMap定义foldr,反之亦然。

foldMap f = foldr (mappend . f) mempty
foldr f z t = appEndo (foldMap (Endo . f) t) z

foldMap :: Monoid m => (a -> m) -> [a] -> m表征列表应该不足为奇,因为列表是一个免费的幺半群。)换句话说,Foldable基本上会将toList作为一个类。 Foldable的实例通过它们有一条“路径”,可以走路给你一个列表; Foldable类型的结构至少与列表一样多。

关于你的疑虑:

  

Foldable不具备head / tail / isEmpty功能,我觉得这更直观。

null :: Foldable t => t a -> Bool是您的isEmpty,您可以使用an appropriate choice of Monoid直接定义head的{​​安全版本}:

head :: Foldable t :: t a -> Maybe a
head = getFirst . foldMap (First . Just)
在我看来,{p> tail有点棘手。 tail甚至对任意类型都意味着什么并不明显。你当然可以写tail :: Foldable t => t a -> Maybe [a](通过toList然后解除反对),但我认为定义T的任何类型tail :: T a -> Maybe (T a)必然在结构上类似于列表(例如Seq)。此外,根据我的经验,绝大多数您认为需要访问列表的tail的案例毕竟是折叠的。

也就是说,抽象不可靠的类型偶尔会有用。例如,megaparsec为(单态)标记流定义了一个Stream类,用作解析器的输入。

答案 1 :(得分:5)

问题

让问题更具体,让我们问:

为什么不是类型类

Warning message:
In `[<-.data.frame`(`*tmp*`, i, value = list(Current.State = integer(0),  :
  provided 2 variables to replace 1 variables

class HasHeadAndTail t where head :: t a -> Maybe a tail :: t a -> Maybe (t a) isEmpty :: t a -> Bool 库中?

答案

此类仅适用于有序的线性容器。 baseMapSetHashMapHashTable都不是实例。我甚至反对将TreeSeq作为一个实例,因为实际上有两个可能的&#34; head&#34;那种结构。

对于任何类型的实例,我们还可以说什么呢?我认为唯一的属性是,如果DList为假,则isEmptyhead应为非tail。因此,isEmpty甚至不应该在课堂上而是一个函数Nothing

所以我的答案是:

  • 这个类在缺少实例的情况下缺乏实用性。
  • 这个类缺乏有用的属性,而且经常不鼓励缺乏属性的类。