【发布时间】:2021-01-14 21:06:30
【问题描述】:
我有一个数据类型定义为
data Foo a = Foo a (a -> a)
Foo 数据构造函数有两个参数值和函数。我需要为此编写 Monad 和 Monad 转换实例。
我正在尝试实现仿函数实例,
instance Functor Foo where
fmap f (Foo x g) = Foo (f x) (g .(f x))
但我收到一个错误Couldn't match type ‘a’ with ‘b’。
这是正确的,因为g 只接受a 类型,而f x 将转换a->b。所以接下来我重写为
instance Functor Foo where
fmap f (Foo x g) = Foo (f x) g
我遇到了同样的错误“无法将类型‘a’与‘b’匹配”。
我也试过了
instance Functor Foo where
fmap f (Foo x g) = Foo (f x) (f. g x)
我得到了Occurs check: cannot construct the infinite type: a ~ b -> a (g.x)
我卡住了,我知道函数g 只接受a 类型并返回a 类型。但fmap 会将a 类型转换为b 类型。我想我也必须在g 上申请fmap,这是我做不到的。
如何编写上述数据类型的实例?
【问题讨论】:
-
你不能因为结果应该是
Foo b (b -> b),但你永远不会将b转换为a,因此你不能使用原始Foo的a -> a构造函数b -> b。除了id函数(即foo (f x) id),你不能fmap它,但可能不符合函子定律。 -
谢谢。这是我参加的课程的作业。我会和我的导师讨论这个问题。可能问题有错字或不正确。
-
@WillemVanOnsem 你能帮我理解为什么我得到“g x”的“无法构造无限类型”吗?
-
@RavitejuaSutrave: 因为它期望
g x应该具有b -> a类型,但它具有a类型,如果b -> a与a类型相同,那么这将导致无限递归类型b -> (b -> (b -> ...)))。 -
请注意,您实际上可以为这种类型编写映射函数,而不是
fmap:它必须具有类型签名foomap :: (a -> b) -> (b -> a) -> Foo a -> Foo b。
标签: haskell monads monad-transformers