[英]Why is Haskell [] (list) not a type class?
我正在编写一个Haskell函数,它以列表作为输入。 也就是说,没有理由它不能成为队列或出队,或任何允许我访问其“头部”及其“尾部”(并检查它是否为空)的东西。 所以[a]输入类型似乎太具体了。 但是AFAIK没有标准的库类型类可以捕获这个接口。 当然,我可以将我的函数包装在Data.Foldable.toList中并使其变为多态wrt可折叠,但这看起来不太正确(惯用)。
为什么没有标准的列表类型类? (为什么Haskell中的“容器”类型层次结构比我认为应该更少?)或者我错过了必要的东西?
给定的代数数据类型可以表示为其变形,一种称为教会编码的变换。 这意味着列表与其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
。 您可以根据foldr
定义foldMap
,反之亦然。
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
as一类。 Foldable
实例有一条通过它们的“路径”,可以走路给你一个列表; Foldable
类型至少具有与列表一样多的结构。
关于你的疑虑:
它不像
Foldable
具有head
/tail
/isEmpty
函数,这是我会发现更直观的。
null :: Foldable t => ta -> Bool
是你的isEmpty
,你可以通过适当选择Monoid
直接定义(一个安全版本) head
:
head :: Foldable t :: t a -> Maybe a
head = getFirst . foldMap (First . Just)
在我看来, tail
有点棘手。 对于任意类型, tail
甚至意味着什么并不明显。 你当然可以编写tail :: Foldable t => ta -> Maybe [a]
(通过toList
ing然后解散),但我认为任何类型T
的tail :: T a -> Maybe (T a)
都是定义的必须在结构上类似于列表(例如Seq
)。 此外,根据我的经验,绝大多数你认为你需要访问列表tail
毕竟是折叠的。
也就是说,抽象不可靠的类型偶尔会有用。 例如, megaparsec
为(单态)标记流定义了一个Stream
类,用作解析器的输入。
问题
让你的问题更具体,让我们问:
为什么不是类型类
class HasHeadAndTail t where
head :: t a -> Maybe a
tail :: t a -> Maybe (t a)
isEmpty :: t a -> Bool
在base
库?
答案
此类仅适用于有序的线性容器。 Map
, Set
, HashMap
, HashTable
和Tree
都不是实例。 我甚至反对将Seq
和DList
作为一个实例,因为该结构实际上有两个可能的“头”。
关于这个类的一个实例,我们还可以说什么呢? 我认为唯一的属性是如果isEmpty
是False那么head
和tail
应该是非Nothing
。 因此,isEmpty甚至不应该在类中,而是一个函数isEmpty :: HashHeadAndTail t => ta -> Bool ; isEmpty = isNothing . head
isEmpty :: HashHeadAndTail t => ta -> Bool ; isEmpty = isNothing . head
isEmpty :: HashHeadAndTail t => ta -> Bool ; isEmpty = isNothing . head
。
所以我的答案是:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.