【问题标题】:Functor instance for datatype containing function包含函数的数据类型的函子实例
【发布时间】: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,因此你不能使用原始Fooa -> a构造函数b -> b。除了id 函数(即foo (f x) id),你不能fmap 它,但可能不符合函子定律。
  • 谢谢。这是我参加的课程的作业。我会和我的导师讨论这个问题。可能问题有错字或不正确。
  • @WillemVanOnsem 你能帮我理解为什么我得到“g x”的“无法构造无限类型”吗?
  • @RavitejuaSutrave: 因为它期望g x 应该具有b -> a 类型,但它具有a 类型,如果b -> aa 类型相同,那么这将导致无限递归类型b -> (b -> (b -> ...)))
  • 请注意,您实际上可以为这种类型编写映射函数,而不是fmap:它必须具有类型签名foomap :: (a -> b) -> (b -> a) -> Foo a -> Foo b

标签: haskell monads monad-transformers


【解决方案1】:

让我们考虑类型,我们基本上需要将Foo a转换为Foo b,这意味着我们需要找到,给定一个函数a -> b,一个a类型的元素和一个函数类型为a -> a,一个元素类型为b,一个函数类型为b -> b

尤其是最后一个比较困难,因为我们只给了一个a -> b类型的函数,而不是一个b -> a类型的函数,我们不能先将输入转换为a,然后通过原始函数,然后将其映射回b

制作满足类型的映射并非完全不可能,例如:

fmap<sub>1</sub> f (Foo x g) = Foo (f x) (<b>const (f x)</b>)

或:

fmap<sub>2</sub> f (Foo x g) = Foo (f x) <b>id</b>

但是fmap<sub>1</sub>fmap<sub>2</sub>的问题需要满足规律:

fmap id = id

换句话说fmap id (Foo x g)需要等于Foo x g,现在如果我们使用idconst (f x),那么idf x并不总是等于g,至少不是如果g 是一个可以采用任何形式的函数。

如果您当然认为Foo x gFoo x (id x) 是等价的,在某些情况下这可能是合理的@leftaroundabout says,那么您可以将其实现为仿函数实例。

【讨论】:

  • IMO 可以让fmap 更改实际数据结构,只要构造函数对模块是“私有的”并且没有导出函数允许观察差异。但这在这个例子中并没有真正的帮助。
  • @leftaroundabout: 是的,或者如果函数的形状有先决条件。
  • 但是 Foo 中的 (a -&gt; a) 可以是 id 以外的任何东西吗?
  • 回答我自己的问题:也可以是const a
  • @pedrofurla 这不正确,它可能是各种各样的事情。提供a -&gt; a 函数的调用者也可以决定a 是什么。例如,他们可以选择Integer,然后(+1) 是正确类型的有效函数。 ida -&gt; a -&gt; a 类型的唯一函数的逻辑适用于您必须提供一个函数(并且其他人可以实例化类型变量)。当你得到一个函数时不是(除非你要实例化类型变量)。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多