Haskell中的替代ZipList实例?
Haskell中的替代ZipList实例?,list,haskell,typeclass,applicative,alternative-functor,List,Haskell,Typeclass,Applicative,Alternative Functor,ZipList附带了一个Functor和一个Applicative实例() 没有好的例子吗 下面提议的那个怎么样? 它有缺陷吗 它没用吗 是否还有其他合理的可能性(比如Bool可以以两种方式成为幺半群),因此两者都不应该是实例 我搜索了“instancealternativeziplist”(用引号首先查找代码),只找到了库、一些教程、课堂讲稿,但没有找到实际的实例 马特·芬威克(Matt Fenwick)说,如果A是()的话,ZipList A只能是幺半群。但是,不管元素类型如何,列表
ZipList
附带了一个Functor
和一个Applicative
实例()
- 没有好的例子吗李>
- 下面提议的那个怎么样?
- 它有缺陷吗
- 它没用吗
- 是否还有其他合理的可能性(比如
可以以两种方式成为幺半群),因此两者都不应该是实例Bool
A
是()的话,ZipList A只能是幺半群。但是,不管元素类型如何,列表都是幺半群
同样的问题讨论了备选方案
实例的外观。他说
对于Zip[1,3,4]Zip[10,20,30,40]
,有两个明智的选择:
Zip[1,3,4]
因为它是第一个-与Zip[10,20,30,40]
因为它最长-与被丢弃的Zip[]
一致Zip
基本上是ZipList
我认为答案应该是Zip[1,3,4,40]
。让我们看看这个例子:
instance Aternative Zip where
empty = Zip []
Zip xs <|> Zip ys = Zip (go xs ys) where
go [] ys = ys
go (x:xs) ys = x : go xs (drop 1 ys)
Ziplits背后的一个直觉是过程:有限或无限的结果流。压缩时,我们组合流,这由Applicative
实例反映出来。当到达列表的末尾时,流不会产生更多的元素。这就是Alternative
实例派上用场的地方:我们可以命名一个并发替换(Alternative,真的),在默认进程终止后立即接管
例如,我们可以编写fmap Just foo pure Nothing
,将ziplistfoo
的每个元素包装成Just
,然后继续执行Nothing
。生成的ziplist是无限的,在所有(实)值用完后恢复为默认值。这当然可以手工完成,在Zip
构造函数中添加一个无限列表。然而,上面的代码更加优雅,并且没有假定构造函数的知识,从而导致更高的代码重用性
我们不需要对元素类型做任何假设(比如作为幺半群本身)。同时,这个定义也不是微不足道的(就像()=const
那样)。它通过对第一个参数进行模式匹配来利用列表结构
上面给出的
的定义是关联的,空列表实际上是空元素。我们有
Zip [] <*> xs == fs <*> Zip [] == Zip [] -- 0*x = x*0 = 0
Zip [] <|> xs == xs <|> Zip [] == xs -- 0+x = x+0 = x
(fs <|> gs) <*> xs == fs <*> xs <|> gs <*> xs
fs <*> (xs <|> ys) == fs <*> xs <|> fs <*> ys
是备选方案的变体(意思是psi x psi y=psi(xy)
和psi x psi y=psi(xy)
)
编辑:对于一些
/许多
方法,我猜
some (Zip z) = Zip (map repeat z)
many (Zip z) = Zip (map repeat z ++ repeat [])
我对
备选方案
的指导直觉来自于解析器,这些解析器建议,如果备选方案的一个分支以某种方式失败,那么应该将其删除,从而导致一个最长的样式的备选方案
,这可能不是非常有用。这将是无偏见的(与解析器不同),但在无限列表中失败
然后,正如您所建议的,它们所要做的就是形成一个幺半群。您的左偏在某种程度上是ZipList
通常无法体现的,尽管您可以很容易地形成备选方案
实例的反射版本。正如您所指出的,这可能也是的惯例,但我不确定ZipList
是否有任何理由遵循这一惯例
我不相信,没有任何合理的部分
或许多
,尽管实际上很少有备选方案
有这些,也许它们最好被隔离到备选方案
的子类中
坦率地说,我不认为你的建议是一个不好的例子,但我不相信它是一个ZipList
所暗示的“替代”例子。也许最好看看这种“扩展”实例还可以应用在哪里(树?),并将其作为库编写。Tags/indes
有趣。一个并非完全无关的想法:ZipLists可以被看作是普通的列表,其中的元素通过它们在列表中(增加)的位置索引进行标记。压缩应用程序通过将索引相等的元素配对来连接两个列表
想象一下,列表中的元素由(非递减)Ord
值标记。Zippery应用程序将相同标记的元素配对,扔掉所有不匹配的元素();zippery alternative可以在标记值上执行保留顺序的左优先并集(常规列表上的alternative也是一种并集)
这完全符合您对索引列表(又称ZipLists)的建议
所以,是的,这是有道理的
溪流
值列表的一种解释是不确定性,这与列表的monad实例一致,但ZipLists可以解释为按顺序组合的同步值流
有了这个流解释,你不会从整个列表的角度来思考,所以选择最长的流显然是欺骗,而在定义中,从第一个ZipList故障切换到第二个ZipList的正确解释是在第一个完成时立即进行,就像你在实例中所说的那样
将两个列表压缩在一起并不仅仅是因为类型签名,而是对
的正确解释
可能最长的列表
将两个列表压缩在一起时,结果是两个长度中的最小值。这是因为这是在不使用⊥. 认为这是两种长度中选择较短的一种是错误的——这是可能的最长长度
类似地,
应生成
zipToMaybe :: Zip a -> Maybe a
zipToMaybe (Zip []) = Nothing
zipToMaybe (Zip (x:_)) = Just x
maybeToZip :: Maybe a -> Zip a
maybeToZip Nothing = Zip []
maybeToZip (Just x) = Zip (repeat x)
some (Zip z) = Zip (map repeat z)
many (Zip z) = Zip (map repeat z ++ repeat [])
instance Alternative Zip where
empty = Zip []
Zip [] <|> x = x
Zip xs <|> _ = Zip xs
instance Alternative ZipList where
empty = ZipList []
ZipList xs <|> ZipList ys = ZipList $ go xs ys where
go [] bs = bs
go as [] = as
go (a:as) (_:bs) = a:go as bs
ZipList xs <|> ZipList ys = ZipList $ xs ++ drop (length xs) ys