[英]Haskell - Custom functor instance on data type with function constructor
我无法为自定义数据类型编写自己的functor实例(无法更改)。 数据类型定义为:
data Foo a = Baz String (Qux -> Foo a) | Bar a
data Qux = None | Quux String
我的问题是为Foo
类型写一个仿函数。 具体来说,我不确定如何将我的函子函数f
正确地应用于Foo
的函数。 我正在考虑以某种方式在构造函数中调用该函数,但是由于我没有任何可用的Qux
,因此我陷入了困境。
instance Functor Foo where
fmap f (Bar a) = Bar (f a)
fmap f (Baz s ???) = Baz s (???) -- What goes here?
-- Clearly, something like this doesn't work
-- fmap f (Baz s g) = Baz s (f g)
-- I've also tried something like this, but I'm not sure where to go from there
-- fmap f (Baz s (None -> Bar b)) = Baz s (f b) ???
-- fmap f (Baz s (Quux x -> Bar b)) = Baz s ???
让我们从完成此等式的左侧开始。 我们可以编写g
将您的函数绑定到变量。
fmap f (Baz sg) = Baz s (???)
然后,我们需要用另一个函数填充问号,该函数采用Qux
并返回Foo b
。
fmap f (Baz sg) = Baz s (\\q -> ???)
我们只能用q
做一件事情,那就是将g
应用于它。
fmap f (Baz sg) = Baz s (\\q -> gq)
但是,这给了我们Foo a
,但是我们需要Foo b
! 我们没有执行此操作的功能。 但是,我们确实有f
,它取a
并返回b
。 如果只有一种方法可以将fmap
a -> b
转换为Foo a -> Foo b
fmap
Foo a -> Foo b
...哦,等等,这就是fmap
!
fmap f (Baz sg) = Baz s (\\q -> fmap f (gq))
如果要以无点符号( https://wiki.haskell.org/Pointfree )编写函数,则可以执行此操作。
fmap f (Baz sg) = Baz s (fmap f . g)
遵循以下类型:
fmap f (Baz s g) = GOAL
-- f :: a -> b
-- s :: String
-- g :: Qux -> Foo a
-- GOAL :: Foo b
因此,我们正在寻找Foo b
(目标行)。 我们可以用Bar
或Baz
制作一个。 fmap
应该保留结构,因此应该是Baz
。 Baz
的String
参数可能不应更改,这只是引起问题的第二个参数。
fmap f (Baz s g) = Baz s GOAL
-- f :: a -> b
-- s :: String
-- g :: Qux -> Foo a
-- GOAL :: Qux -> Foo b
现在我们必须做一个Qux -> Foo b
。 如果需要执行功能,lambda是必不可少的工具(有其他工具,但是lambda是祖父)。 所以做一个lambda:
fmap f (Baz s g) = Baz s (\x -> GOAL)
-- f :: a -> b
-- s :: String
-- g :: Qux -> Foo a
-- x :: Qux <-- NEW
-- GOAL :: Foo b
注意,我们现在有一个x :: Qux
可以使用。 使用g
和x
可以创建Foo a
,然后递归使用fmap f
1可以生成所需的Foo b
。
请注意,我是如何一次仅一步一步地填写表达式,用目标替换未知参数,然后退后一步来考虑范围内的变量以及它们的类型。 继续执行此操作,直到明确目标的路径。
1递归类型通常将具有相应的递归fmap
定义。 递归在fmap
发生的fmap
与类型递归的方式完全对应。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.