Haskell 通用容器转换?如果从可折叠到替代?

Haskell 通用容器转换?如果从可折叠到替代?,haskell,containers,applicative,foldable,alternative-functor,Haskell,Containers,Applicative,Foldable,Alternative Functor,对于实例备选方案[],()=(++)。因此,我将()视为某种拼接器,从而产生了看似通用的容器转换器: -- (<|>) = generalization of (++) (<|) :: Alternative f => x -> f x -> f x x <| xs = pure x <|> xs conv :: (Foldable t, Alternative f) => t x -> f x conv = foldr (&

对于
实例备选方案[]
()=(++)
。因此,我将
()
视为某种拼接器,从而产生了看似通用的容器转换器:

-- (<|>) = generalization of (++)

(<|) :: Alternative f => x -> f x -> f x
x <| xs = pure x <|> xs

conv :: (Foldable t, Alternative f) => t x -> f x
conv = foldr (<|) empty
此外,这种类比还产生了一些有趣的新实例,例如用于函子和的工作应用函子(
Data.functor.Sum
):

实例(可折叠f、应用f、备选方案g)=>Applicative(总和f g),其中
纯=InL。纯净的
InL f InL x=InL(f x)
InL f InR x=InR(转换f x)
InR f InL x=InR(f conv x)
印度卢比f印度卢比x=印度卢比(f x)
实例(可折叠f、应用程序f、备选方案g)=>备选方案(总和f g),其中
空=印度卢比空
InL x ux=InL x
InR InL y=InL y
印度卢比x印度卢比y=印度卢比(x y)
用这种类比概括所有函数并创建新实例,特别是列表操作,这真的是个好主意吗

编辑:我特别关注不明确的返回类型。对于正常的列表操作,返回类型可以从其参数类型中推断出来。但“通用”版本不是,因为必须显式指定返回类型。这个问题是否严重到可以认为这个类比是危险的?(或者还有其他问题吗?)


编辑2:如果我准确地理解了
foldl'
的行为,universal
splitAt
(如上所示)的时间复杂度必须是
Θ(长度xs)
,因为
foldl'
对每个元素都是严格的,对吗?如果是,那一定是个问题,因为它不如常规版本的
Θ(minn(length xs))

使函数在理论上尽可能具有多态性并不总是一个好主意,尤其是函数参数。根据经验:使函数结果尽可能具有多态性。(通常情况下,参数已经包含结果中使用的一些类型变量。)只有在有特定原因的情况下,也要为参数提供额外的多态性

原因是:如果所有的东西都是多态的,编译器就没有关于选择什么具体类型的提示。多态性结果/值通常是可以的,因为它们通常直接或间接地绑定到具有显式签名的顶级定义,但多态性参数通常只填充文字(在Haskell中,数字文字是多态的,字符串/列表也可以是多态的)或其他多态性值,因此,您必须键入大量显式本地签名,这往往比偶尔插入显式转换函数更加尴尬,因为某些内容不够多态


使用
Foldable->Alternative
的这个想法还有另一个问题,即
Alternative
类没有非常坚实的数学基础,因此不受欢迎。它基本上是一类应用函子,对于每个实例化,它都会产生一个
幺半群。这也可以通过要求
幺半群本身来直接表达。因此,“通用容器转换函数”已经存在,它是
纯的

我投票关闭,因为“不清楚你在问什么”。你能更具体地说明你的担忧,或者你在一个可接受的答案中寻找什么样的信息吗?关于建议的
foldall
。关于
splitAt
我特别关注的
splitAt::fa->(ga,fa)
我承认这可能是明智的,但是
ta->(fa,ga)
绝对不是因为您希望能够从O(l)中的列表中分割出k个l元素块⋅ k) 时间,即使列表是无限的。如果RHS每次都必须进行nop转换,则会变成O(l⋅ k²)
Foldable
本身可以说是多态参数的参数:容器类型仅出现在方法的参数中。我想我们只是幸运,人们没有对
core草书
可展开的东西做太多折叠。
-- fmap = generalization of map

reverse :: (Foldable t, Alternative f) => t a -> f a
reverse = getAlt . getDual . foldMap (Dual . Alt . pure)

-- asum = generalization of concat

asumMap :: (Foldable t, Alternative f) => (a -> f b) -> t a -> f b -- generalization of concatMap
asumMap f = getAlt . foldMap (Alt . f)

splitAt :: (Foldable t, Alternative f, Alternative g) => Int -> t a -> (f a, g a)
splitAt n xs = let (_,fs,gs) = foldl' (\(i,z1,z2) x -> if 0 < i then (i-1,z1 . (x <|),z2) else (0,z1,z2 . (x <|))) (n,id,id) xs in (fs empty,gs empty)
instance (Foldable f, Applicative f, Alternative g) => Applicative (Sum f g) where
    pure = InL . pure
    InL f <*> InL x = InL (f <*> x)
    InL f <*> InR x = InR (conv f <*> x)
    InR f <*> InL x = InR (f <*> conv x)
    InR f <*> InR x = InR (f <*> x)

instance (Foldable f, Applicative f, Alternative g) => Alternative (Sum f g) where
    empty = InR empty
    InL x <|> _ = InL x
    InR _ <|> InL y = InL y
    InR x <|> InR y = InR (x <|> y)