Haskell-具有函数构造函数的数据类型上的自定义函子实例
我无法为无法更改的自定义数据类型编写自己的functor实例。数据类型定义为:Haskell-具有函数构造函数的数据类型上的自定义函子实例,haskell,functor,Haskell,Functor,我无法为无法更改的自定义数据类型编写自己的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 (Ba
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 s g=Baz s 然后,我们需要用另一个函数填充问号,该函数接受一个Qux并返回一个foob fmap f Baz s g=Baz s\q-> 对于q,我们只能做一件事,那就是将g应用于它 fmap f Baz s g=Baz s\q->g q 然而,这给了我们一个Foo a,但我们需要一个Foo b!我们没有这样做的功能。然而,我们有f,它取a,返回b。如果有办法把a->b变成Foo a->Foo b。。。哦,等等,有,它叫fmap fmap f Baz s g=Baz s\q->fmap f g q 如果您想用无点表示法编写函数,可以这样做
fmap f Baz s g=Baz s fmap f。g让我们从完成这个等式的左侧开始。我们可以编写g来将函数绑定到变量 fmap f Baz s g=Baz s 然后,我们需要用另一个函数填充问号,该函数接受一个Qux并返回一个foob fmap f Baz s g=Baz s\q-> 对于q,我们只能做一件事,那就是将g应用于它 fmap f Baz s g=Baz s\q->g q 然而,这给了我们一个Foo a,但我们需要一个Foo b!我们没有这样做的功能。然而,我们有f,它取a,返回b。如果有办法把a->b变成Foo a->Foo b。。。哦,等等,有,它叫fmap fmap f Baz s g=Baz s\q->fmap f g q 如果您想用无点表示法编写函数,可以这样做 fmap f Baz s g=Baz s fmap f。g遵循以下类型:
fmap f (Baz s g) = GOAL
-- f :: a -> b
-- s :: String
-- g :: Qux -> Foo a
-- GOAL :: Foo b
所以我们正在寻找一个球线。我们可以用吧台或巴兹做一个。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
现在我们要做一首曲子->福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 f (Baz s g) = GOAL
-- f :: a -> b
-- s :: String
-- g :: Qux -> Foo a
-- GOAL :: Foo b
所以我们正在寻找一个球线。我们可以用吧台或巴兹做一个。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
现在我们要做一首曲子->福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中递归发生的位置与类型的递归方式完全对应。第一部分很简单:Baz是两种类型的产物,因此您只需要在Baz s g上进行模式匹配,其中g::Qux->Foo a。如何处理g是一个棘手的部分:在Haskell中,考虑这一点的方法通常是遵循类型。你有一个函数f::a->b,一个我称之为g的函数,类型为Qux->fooa,你想要一个类型为Qux->foob的函数。我敢肯定,只有一种方法可以利用这里的数据来实现这一点——要看到这一点,不要害怕使用递归;第一部分很简单:Baz是两种类型的产品,所以您只需要在Baz上进行模式匹配,其中g::Qux->fooa。如何处理g是一个棘手的部分:A
在Haskell中,思考这个问题的方法就是遵循类型。你有一个函数f::a->b,一个我称之为g的函数,类型为Qux->fooa,你想要一个类型为Qux->foob的函数。我敢肯定,只有一种方法可以利用这里的数据来实现这一点——要看到这一点,不要害怕使用递归;非常感谢!这就是我遇到的问题。我忘了我可以用兰姆达斯那样的。非常感谢!这就是我遇到的问题。我忘了我可以像那样使用lambdas。