我具有以下带有Monoid和Semigroup实例的数据类型:
newtype Combine a b =
Combine { unCombine :: a -> b }
instance (Semigroup b)
=> Semigroup (Combine a b) where
Combine {unCombine=f} <> Combine {unCombine=g} = Combine (f <> g)
instance (Semigroup b, Monoid b)
=> Monoid (Combine a b) where
mempty = Combine mempty
mappend = (<>)
我要配置它,函数
mempty
的(->)
值是多少?我尝试过例如:
*Exercises Data.Monoid> mempty :: (-> Integer Bool)
<interactive>:21:15: error: parse error on input `Integer'
mempty
中monoid
的实现是什么样的?我查看了黑客源:
instance Monoid b => Monoid (a -> b) where
mempty _ = mempty
mappend f g x = f x `mappend` g x
并且找不到
mempty
的实现。也许要弄清楚我的意思,请考虑以下示例:
*Exercises Data.Monoid> mempty :: (Product Integer)
Product {getProduct = 1}
Product Integer
的空位是Product {getProduct = 1}
。 最佳答案
类型构造函数(->)
不是类型常量(没有任何类型的(->)
值),因此不能有一个monoid实例。
如果类型b
具有一个monoid实例,则类型常量a -> b
(或(->) a b
)确实具有一个monoid实例,并且mempty
产生一个函数,该函数将忽略其输入并返回mempty
的b
值。
如果你看
instance Monoid b => Monoid (a -> b) where
mempty _ = mempty
mappend f g x = f x `mappend` g x
mempty _ = mempty
行实现了这一点。mempty
的a -> b
是什么类型?它是a -> b
,因为mempty
必须是a -> b
类型的值。所以mempty _ = mempty
告诉我们,
mempty
的a -> b
是一个函数,它将丢弃其输入并返回mempty
,即类型为b
的值。在此定义中两次出现的名称mempty
表示不同的功能/值。让我们举一些具体的例子:
你试过了
mempty :: (-> Integer Bool)
这在语法上是错误的。你想尝试
mempty :: (->) Integer Bool
产生一个新的错误
<interactive>:5:1: error:
• No instance for (Monoid Bool) arising from a use of ‘mempty’
• In the expression: mempty :: (->) Integer Bool
In an equation for ‘it’: it = mempty :: (->) Integer Bool
因为
Bool
没有一个monoid实例。你试过了
mempty :: (Product Integer)
它起作用并产生
Product {getProduct = 1}
作为值。这就告诉您
Product Integer
有一个monoid实例。因此,我们可以尝试将Product Integer
设置为b
中的a -> b
类型。现在尝试
> let f = mempty :: a -> Product Integer
> f 'x'
Product {getProduct = 1}
在此示例中,
mempty
引用类型为a -> Product Integer
的某个值,因此是一个函数。因此,在这种情况下,来自t
的类型变量mempty :: (Monoid t) => t
引用类型a -> Product Integer
。关于haskell - 数据类型的含义是什么?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/44818972/