Haskell中用于可前置列表的Data.List和Data.Sequence的最小接口
我发现我正在编写重复函数来处理Data.List和Data.Sequence,为了对它们进行概括,我写了:Haskell中用于可前置列表的Data.List和Data.Sequence的最小接口,haskell,Haskell,我发现我正在编写重复函数来处理Data.List和Data.Sequence,为了对它们进行概括,我写了: import qualified Data.Sequence as Seq class PrependableList pl where empty :: pl a first :: pl a -> a prepend :: a -> pl a -> pl a len :: pl a -> Int instance PrependableLis
import qualified Data.Sequence as Seq
class PrependableList pl where
empty :: pl a
first :: pl a -> a
prepend :: a -> pl a -> pl a
len :: pl a -> Int
instance PrependableList [a] where
empty = []
first = head
prepend = (:)
len = length
instance PrependableList (Seq.Seq a) where
empty = Seq.empty
first seq = Seq.index seq 0
prepend = (Seq.<|)
len = Seq.length
从我在其他条目(例如)中看到的情况来看,可能不可能完全概括多个类似列表的数据结构
但是,上述4个函数是否至少可以推广到Data.List和Data.Sequence?多亏了大家,这是正确的代码,只提供了一个简单的用法示例:
import qualified Data.Sequence as Seq
class PrependableList pl where
empty :: pl a
first :: pl a -> a
prepend :: a -> pl a -> pl a
len :: pl a -> Int
instance PrependableList [] where
empty = []
first = head
prepend = (:)
len = length
instance PrependableList Seq.Seq where
empty = Seq.empty
first seq = Seq.index seq 0
prepend = (Seq.<|)
len = Seq.length
-- Example usage
prependAll :: (PrependableList pl) => pl a -> [a] -> pl a
prependAll plist xs = foldr prepend plist xs
main = do
print $ prependAll Seq.empty [1..5]
print $ prependAll [] [1..5]
感谢大家,这是正确的代码,只提供了一个简单的用法示例:
import qualified Data.Sequence as Seq
class PrependableList pl where
empty :: pl a
first :: pl a -> a
prepend :: a -> pl a -> pl a
len :: pl a -> Int
instance PrependableList [] where
empty = []
first = head
prepend = (:)
len = length
instance PrependableList Seq.Seq where
empty = Seq.empty
first seq = Seq.index seq 0
prepend = (Seq.<|)
len = Seq.length
-- Example usage
prependAll :: (PrependableList pl) => pl a -> [a] -> pl a
prependAll plist xs = foldr prepend plist xs
main = do
print $ prependAll Seq.empty [1..5]
print $ prependAll [] [1..5]
我知道你已经自己回答了这个问题,但我想指出的是,Haskell近年来一直在努力更广泛地封装这些想法,而你的类已经是其他两个现有类的组合:
进口控制。单子单子,mzero,mplus;
导入数据。可折叠,长度,toList;
导入数据
导入符合条件的数据。顺序为S
-与您的PrependableList相同
类可前置的p,其中
空::p a
第一:p a->a
前置::a->PA->PA
len::pa->Int
-通用新型包装器
新类型WrapP px=WrapP{unwrapP::px}派生Show,Eq,Ord
-任何可折叠的monadplus都是可预折叠的。
实例MonadPlus m,Foldable m=>Prependable WrapP m其中
空=WrapP mzero
prepend=WrapP。打开包装。mplus。回来
第一个=头。托利斯特。展开
len=长度。展开
-具体案例
类型SeqP x=包装Seq x
类型ListP x=WrapP[]x
此外,由于WrapP是一种新类型,您通常可以用id替换WrapP和unwrapP,只要您还调整了类型签名;特别是,我们可以将您的四个函数直接编写为:
空::可折叠的m,MonadPlus m=>mx
空=零
第一个::可折叠的m,MonadPlus m=>mx->x
第一个=头。托利斯特
可折叠的m,MonadPlus m=>x->MX->MX
prepend=mplus。回来
len::可折叠的m,MonadPlus m=>mx->Int
len=长度
现在这些将在列表和Data.Sequence上运行。如果Prelude.length与Data.Foldable.length不同,则可能需要更新的ish版本的GHC,或者必须导入Prelude隐藏长度,然后从Data.Foldable显式导入
由于Data.Sequence已经为Seq定义了MonadPlus和Foldable,您可以使用8行代码,而不需要新的类或实例声明;此外,其中两个是长度的直接替换len,mzero为空,如果您只使用已经为您定义的版本,则可以再节省4行代码
作为一个小小的迂回,首先也是从控件中提取。Comonad,用一个非空的!列表的摘录是head,副本是take,而不是。无效的尾部使用Data.List.tails,但忽略最后一个元素[]。我不认为你可以纯粹基于一个Comonad基础设施来定义len;为此,你真的需要一个可折叠的类型。通过将非空列表写成newtype NEList=NEList x Maybe NEList x,我们可以将其替换为Cofree Maybe,从而使其成为明显的comonad形式。
我知道你已经自己回答了这个问题,但我想指出的是,Haskell近年来一直在努力更广泛地封装这些想法,而你的类已经是其他两个现有类的组合:
进口控制。单子单子,mzero,mplus;
导入数据。可折叠,长度,toList;
导入数据
导入符合条件的数据。顺序为S
-与您的PrependableList相同
类可前置的p,其中
空::p a
第一:p a->a
前置::a->PA->PA
len::pa->Int
-通用新型包装器
新类型WrapP px=WrapP{unwrapP::px}派生Show,Eq,Ord
-任何可折叠的monadplus都是可预折叠的。
实例MonadPlus m,Foldable m=>Prependable WrapP m其中
空=WrapP mzero
prepend=WrapP。打开包装。mplus。回来
第一个=头。托利斯特。展开
len=长度。展开
-具体案例
类型SeqP x=包装Seq x
类型ListP x=WrapP[]x
此外,由于WrapP是一种新类型,您通常可以用id替换WrapP和unwrapP,只要您还调整了类型签名;特别是,我们可以将您的四个函数直接编写为:
空::可折叠的m,MonadPlus m=>mx
空=零
第一个::可折叠的m,MonadPlus m=>mx->x
第一个=头。托利斯特
可折叠的m,MonadPlus m=>x->MX->MX
prepend=mplus。回来
len::可折叠的m,MonadPlus m=>mx->Int
len=长度
现在这些将在列表和Data.Sequence上运行。如果Prelude.length与Data.Foldable.length不同,则可能需要更新的ish版本的GHC,或者必须导入Prelude隐藏长度,然后从Data.Foldable显式导入
作为Data.Sequence已经为Seq定义了MonadPlus和Foldable,
您可以使用8行代码,没有新的类或实例声明;此外,其中两个是长度的直接替换len,mzero为空,如果您只使用已经为您定义的版本,则可以再节省4行代码
作为一个小小的迂回,首先也是从控件中提取。Comonad,用一个非空的!列表的摘录是head,副本是take,而不是。无效的尾部使用Data.List.tails,但忽略最后一个元素[]。我不认为你可以纯粹基于一个Comonad基础设施来定义len;为此,你真的需要一个可折叠的类型。通过将非空列表写成newtype NEList=NEList x Maybe NEList x,我们可以将非空列表替换为Cofree Maybe,看看它是一个comonad。只需将[A]更改为[]。正如错误消息所指出的,PrependableList需要一元类型构造函数*->*,而不是空类型构造函数*。因此,您应该编写实例PrependableList[]和实例PrependableList Seq.Seq。此外,除非使用限定名Thanke@MathematicalArchid,否则代码片段不会编译,这确实克服了编译错误。接下来的问题是如何在函数的类型定义中使用PrependableList。当我添加PrependableList a时,编译器指出了另一种类型的不匹配:kind mis match PrependableList的第一个参数'should has kind*->',但是'has kind'不能使星号正确显示anks@Jubobs-修复了Seq。@AlbertCardona您想要类似PrependableList pl=>pl a的东西。只需将[a]改为[]。正如错误消息所指出的,PrependableList需要一元类型构造函数*->*,而不是空构造函数*。因此,您应该编写实例PrependableList[]和实例PrependableList Seq.Seq。此外,除非使用限定名Thanke@MathematicalArchid,否则代码片段不会编译,这确实克服了编译错误。接下来的问题是如何在函数的类型定义中使用PrependableList。当我添加PrependableList a时,编译器指出另一种类型不匹配:kind mis match PrependableList的第一个参数'should has kind*->',但是'has kind'不能使星号正确显示anks@Jubobs-修复了Seq。@AlbertCardona您想要类似PrependableList pl=>pl a的东西。
$ ./pl
fromList [1,2,3,4,5]
[1,2,3,4,5]