Haskell 应用程序/Monad实例对Sum和Product有什么用途?

Haskell 应用程序/Monad实例对Sum和Product有什么用途?,haskell,typeclass,Haskell,Typeclass,我对Sum和Product新类型的理解是,它们充当数字类型的单项式包装器。我会理解它们上面的Functor实例,但为什么还有Applicative,Monad任何其他看似无用的实例?我知道它们在数学上是正常的(同构于Identitymodad,对吗?),但用例是什么?例如,如果有一个Applicative Sum实例,我希望在某处遇到类型为Sum(a->b)的值。我无法想象这在哪里可能有用。这样的值通常是由于部分应用了二进制运算符。假设Functor和Applicative实例如下 import

我对
Sum
Product
新类型的理解是,它们充当数字类型的单项式包装器。我会理解它们上面的
Functor
实例,但为什么还有
Applicative
Monad
任何其他看似无用的实例?我知道它们在数学上是正常的(同构于
Identity
modad,对吗?),但用例是什么?例如,如果有一个
Applicative Sum
实例,我希望在某处遇到类型为
Sum(a->b)
的值。我无法想象这在哪里可能有用。

这样的值通常是由于部分应用了二进制运算符。假设
Functor
Applicative
实例如下

import Control.Applicative
import Data.Monoid

instance Functor Sum where
    fmap f (Sum x) = Sum (f x)

instance Applicative Sum where
    pure = Sum
    (Sum f) <*> (Sum x) = Sum (f x)

这样的实例便于提升任意函数来处理当前恰好位于
Sum
Product
中的内容。例如,人们可能会想象,想要在某种东西上执行一些位运算,但在
求和
中要比裸运算更方便;然后
liftA2(.&.)::Sum Int->Sum Int->Sum Int
(例如)


我们也可以通过为
Sum
提供一个
Bits
实例来提供这种操作,但是推广这种技术需要
Sum
的实现者预测可能要做的每一个操作,这似乎是一项艰巨的任务。提供
Applicative
Monad
实例为用户提供了一个一劳永逸的翻译,以提升他们喜欢的任何功能——包括那些
Sum
的实现者没有预料到的有用功能。

我同意,这些实例似乎毫无意义。“因为我们可以”的明显例子。我现在没有访问GHCi的权限,但它们是否可以用于执行类似
x::Sum Int;x=do{1;2;3;4;5}
?@bheklirit“起作用”,并返回
Sum 5
,因为
Sum
是身份单子。似乎可以做类似的事情:
x::Sum Int;x=do{Sum 1;Sum 2}
),并通过说
(>>)=mappend
Sum 5*Sum 10
也有效,因为
Num
实例。是的,但这可以说是对
Applicative
类的滥用。用于此目的更好。@leftaroundabout您能仔细说说
Iso
combinator的优点吗?天真地说,它们看起来像是一种奇怪的权衡:这是一种非常严重的依赖关系(当然不是一个应该放在基中的依赖关系),当我看
au
auf
时,与单个
liftA2
@leftaroundabout应用程序相比,提升两个或更多参数函数的语法看起来冗长,“我的眼睛亮了起来。@DanielWagner嗯,我并没有特别建议在
Sum
上使用
镜头来完成
liftA2(.&.
)。这当然是不明智的。我实际上的意思是,将
Sum
值包装起来并将它们像这样组合起来并没有多大好处–这些新类型的目的是让您可以将它们注入到一个单一的算法中,该算法可以在幺半群上工作,但您希望与数字一起使用,但实际上不会得到类型
Sum Int
的结果。换句话说,我把
Sum
更多地理解为一个标签,你可以传递给函数来解释如何处理数字,而不是作为一个实际的类型构造函数……因此,我也觉得除了这些新类型所涉及的
Monoid
之外,给它们任何实例都是不合理的iso组合器使单个操作更容易将数字“标记包装”为
Sum
in,而无需再次手动包装和展开。如果
lens
在很大程度上是依赖性的,那么您也可以使用它们。
> :t (*) <$> (Sum 5)
(*) <$> (Sum 5) :: Num a => Sum (a -> a)

> (*) <$> (Sum 5) <*> (Sum 10)
Sum {getSum = 50}