Data.List
定义
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
unfoldr f b = case f b of
Just (a,new_b) -> a : unfoldr f new_b
Nothing -> []
有许多函数几乎可以使用unfoldr
定义,但在列表的最后有问题。一个简单的"修复"是
unfoldr' :: (b -> Either (a,b) [a]) -> b -> [a]
unfoldr' f b = case f b of
Left (a, new_b) -> a : unfoldr' f new_b
Right r -> r
此功能是否具有标准名称?它是否具有良好的属性并与foldr
良好互动?
答案 0 :(得分:2)
与递归方案中的elgot类似,我认为。
扩展并再次查看,它可能只是来自同一个包的apo
。该函数的类型为(Unfoldable t, Foldable t) => (a -> Base t (Either t a)) -> a -> t
。将a
重命名为b
并将t
改为[a]
,我们会(b -> Base [a] (Either [a] b)) -> b -> [a]
。
查看Base [a] (Either [a] b)
部分需要引用源代码,但为我们提供了一个只有少数构造函数的数据系列:Cons a (Left [a])
,Cons a (Right b)
和Nil
。现在,您的类型Either (a, b) [a]
也只有少数构造函数:Left (a, b)
,Right (a:[a])
和Right []
。我想你可以看到这两种类型之间存在同构。这是一方:
e2pe :: Either (a, b) [a] -> Prim [a] (Either [a] b)
e2pe (Left (x,y)) = Cons x $ Right y
e2pe (Right (x:xs)) = Cons x $ Left xs
e2pe (Right []) = Nil
我的(未经证实)声明是unfoldr' f
= apo $ e2pe . f
。
在定义unfoldr'
和我的e2pe
:
GHCi> let f n = case compare n 0 of { EQ -> Right []; LT -> Left (n, succ n); GT -> Left (n, pred n); }
GHCi> unfoldr' f 5
[5,4,3,2,1]
GHCi> apo (e2pe . f) 5
[5,4,3,2,1]
GHCi> unfoldr' f (-5)
[-5,-4,-3,-2,-1]
GHCi> apo (e2pe . f) (-5)
[-5,-4,-3,-2,-1]
GHCi> let f n = case compare n 0 of { EQ -> Right [0]; LT -> Left (n, succ n); GT -> Left (n, pred n); }
GHCi> unfoldr' f 5
[5,4,3,2,1,0]
GHCi> unfoldr' f (-5)
[-5,-4,-3,-2,-1,0]
GHCi> apo (e2pe . f) 5
[5,4,3,2,1,0]
GHCi> apo (e2pe . f) (-5)
[-5,-4,-3,-2,-1,0]
如果我的主张是正确的,那么你已经彻底改变了这种同态。
答案 1 :(得分:1)
(这是一个评论,有些代码所以它不适合)考虑你在评论中提到的测试用例,
f xs -- = zip (map reverse $ inits xs) (tails xs)
= unfoldr g (Just ([],xs))
where
g (Just (acc,xs@[])) = Just ( (acc,xs), Nothing)
g (Just (acc,xs@(x:t))) = Just ( (acc,xs), Just (x:acc, t) )
g Nothing = Nothing
感知到的问题是对列表的一个额外处理节拍 end ,这迫使我们使用嵌套的Maybe
。事实上,你的函数更容易(不需要嵌套的Maybe
):
= unfoldr' h ([],xs)
where
h (acc,xs@[]) = Right [ (acc,xs) ] -- last tail
h (acc,xs@(x:t)) = Left ( (acc,xs), (x:acc,t) )
但我们也可以用另一种方式简化g
代码:
= unfoldr (fmap g') (Just ([],xs))
where
g' (acc,xs@[]) = ( (acc,xs), Nothing) -- last element
g' (acc,xs@(x:t)) = ( (acc,xs), Just (x:acc, t) )
并将其用作此类函数的框架,标准unfoldr
仍然存在。或者,Nothing
的定义中可能还有一行g
代码,无需担心。
但当然,如果您真的需要在列表中添加特殊尾部,而不仅仅是一个元素,那么它就无法替代。