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}