2

对于instance Alternative [], (<|>) = (++). 所以我把(<|>)它当成某种拼接器,导致看似几乎万能的容器转换器:

-- (<|>) = 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.List,这里有一些:

-- 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)

此外,这个类比产生了一些有趣的新实例,例如函子 sum ( Data.Functor.Sum) 的工作应用函子:

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)

用这个类比概括所有函数并创建新实例实际上是个好主意,尤其是对于列表操作?

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

编辑 2:如果我foldl'完全理解 的行为,universal 的时间复杂度splitAt(如上所示)必须是Θ(length xs)foldl'对于每个元素都是严格的,对吧?如果是,那一定是个问题,因为它不如普通版本的Θ(min n (length xs)).

4

1 回答 1

3

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

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

这个想法Foldable->Alternative特别有另一个问题,该Alternative课程相当不受欢迎,没有非常坚实的数学支持。它基本上是一类应用函子,对于每个实例化都会产生一个Monoid. 嗯,这也可以通过要求Monoid本身来直接表达。“通用容器转换功能”因此已经存在,它是foldMap pure

于 2018-02-08T12:20:34.893 回答