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
      可以以两种方式成为幺半群),因此两者都不应该是实例
我搜索了“instancealternativeziplist”(用引号首先查找代码),只找到了库、一些教程、课堂讲稿,但没有找到实际的实例

马特·芬威克(Matt Fenwick)说,如果
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
    ,将ziplist
    foo
    的每个元素包装成
    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