为什么非多态类型不能在 Haskell 中实现 Foldable?
Why can't a non-polymorphic type implement Foldable in Haskell?
假设我有一些简化的 lisp 风格 Expr
类型如下
data Expr = String String | Cons Expr Expr
deriving (Show)
我可以创建列表作为 Cons-cells 的 Cons-cells:
Cons (String "hello") (Cons (String "World") (String "!"))
据此我想为 Expr
实现 Foldable
以折叠这些缺点列表 - 但这是不可能的,因为 Foldable
需要一种类型 * -> *
(即只有一个类型参数的多态),其中我的 Expr
有种类 *
.
这是为什么?对我来说,像这种情况下折叠非多态类型似乎是完全合理的,但显然我遗漏了一些东西。
To me it seems like folding over non-polymorphic types like in this case would be perfectly reasonable, but obviously I'm missing something.
确实很有道理。折叠单形容器的一种方法是使用 MonoFoldable
. Another is using a Fold
from lens,或来自其他光学库:
import Control.Lens
data Expr = String String | Cons Expr Expr
deriving (Show)
-- A Traversal can also be used as a Fold.
-- strings :: Applicative f => (String -> f String) -> (Expr -> f Expr)
strings :: Traversal' Expr String
strings f (String s) = String <$> f s
strings f (Cons l r) = Cons <$> strings f l <*> strings f r
GHCi> hello = Cons (String "hello") (Cons (String "World") (String "!"))
GHCi> toListOf strings hello
["hello","World","!"]
GHCi> import Data.Monoid
GHCi> foldMapOf strings (Sum . length) hello
Sum {getSum = 11}
至于为什么 Foldable
个实例的种类是 * -> *
而不是 *
,我将其归结为简单性和历史原因的结合。从历史上看,Foldable
是 Traversable
的一个分支,值得注意的是,虽然单态遍历很有用,但它们的局限性比影响单态折叠的那些更显着(例如,您可以'从他们那里恢复 fmap
,但只是一个单态的 omap
)。最后,Joseph Sible Is there anything we lose with MonoFoldable? 建议的问答包括一些有趣的讨论,其中讨论了不将 Foldable
完全替换为 MonoFoldable
的潜在原因。
假设我有一些简化的 lisp 风格 Expr
类型如下
data Expr = String String | Cons Expr Expr
deriving (Show)
我可以创建列表作为 Cons-cells 的 Cons-cells:
Cons (String "hello") (Cons (String "World") (String "!"))
据此我想为 Expr
实现 Foldable
以折叠这些缺点列表 - 但这是不可能的,因为 Foldable
需要一种类型 * -> *
(即只有一个类型参数的多态),其中我的 Expr
有种类 *
.
这是为什么?对我来说,像这种情况下折叠非多态类型似乎是完全合理的,但显然我遗漏了一些东西。
To me it seems like folding over non-polymorphic types like in this case would be perfectly reasonable, but obviously I'm missing something.
确实很有道理。折叠单形容器的一种方法是使用 MonoFoldable
. Another is using a Fold
from lens,或来自其他光学库:
import Control.Lens
data Expr = String String | Cons Expr Expr
deriving (Show)
-- A Traversal can also be used as a Fold.
-- strings :: Applicative f => (String -> f String) -> (Expr -> f Expr)
strings :: Traversal' Expr String
strings f (String s) = String <$> f s
strings f (Cons l r) = Cons <$> strings f l <*> strings f r
GHCi> hello = Cons (String "hello") (Cons (String "World") (String "!"))
GHCi> toListOf strings hello
["hello","World","!"]
GHCi> import Data.Monoid
GHCi> foldMapOf strings (Sum . length) hello
Sum {getSum = 11}
至于为什么 Foldable
个实例的种类是 * -> *
而不是 *
,我将其归结为简单性和历史原因的结合。从历史上看,Foldable
是 Traversable
的一个分支,值得注意的是,虽然单态遍历很有用,但它们的局限性比影响单态折叠的那些更显着(例如,您可以'从他们那里恢复 fmap
,但只是一个单态的 omap
)。最后,Joseph Sible Is there anything we lose with MonoFoldable? 建议的问答包括一些有趣的讨论,其中讨论了不将 Foldable
完全替换为 MonoFoldable
的潜在原因。