我需要为Flip数据类型编写 Functor 实例:
data K a b = K a
newtype Flip f a b = Flip (f b a) deriving (Eq, Show)
instance Functor (Flip K a) where
fmap=undefined
我在课堂上给出的解决方案是:
instance Functor (Flip K a) where
    fmap f (Flip (K b)) = Flip (K (f b))
我真的不明白这里发生了什么,我开始怀疑我对数据类型和函子的整体理解。我所理解的是这个(如果有任何错误,请纠正我):
K是一种将 2 个参数转换为结构的数据类型K a(仅保留第一个参数)Flip 是一种将 3 个参数转换为一个结构的数据类型fmap :: (a-> b) -> f a -> f b,f a有种*,要写 Functor 的实例Flip,我们把它写在最后一个类型 in 上Flip。Akaf和a在某种程度上是“常数”,我们为 type 编写函子b。我会写这样的东西:instance Functor (Flip f a) where
   fmap f (Flip x y z) = fmap Flip x y (f z)
我知道这是完全错误的,但我不知道为什么。
另外,我们为什么要引入KFlip 的 Functor 实例?有人可以彻底解释提出这个解决方案的过程以及为什么它是正确的吗?
K是一种将 2 个参数转换为结构的数据类型K a(仅保留第一个参数)
这不太对。  K a b是一种使用两个参数形成的数据类型,但说它“将它们变成”任何东西都是不对的。相反,它只是向世界说明现在存在一种新类型:K a b. “所以呢?” 你可能会问。好吧,数据类型的后半部分定义了如何创建这种类型的新值。那部分说,“您可以K a b使用我将调用的K具有 type 的函数创建一个新的 type 值a -> K a b。” 这是真正重要的是要认识到的是区分类型 K和构造 K。
所以,并不是K“只保留第一个参数”——而是构造函数K(它是一个函数)碰巧不接受任何类型的参数b。
Flip是一种将 3 个参数转换为一个结构的数据类型
如上所述,这并不完全正确。该Flip声明指出,有可能是类型的值Flip f a b,并让他们的唯一方法是使用构造Flip有型f b a -> Flip f a b。
如果您想知道我是如何想出构造函数K和的类型签名的Flip,它实际上并不神秘,您可以通过键入:t K或:t Flip到 GHCi 中进行仔细检查。这些类型完全根据数据类型声明的右侧进行分配。另请注意,类型名称和构造函数不必相同。例如,考虑以下数据类型:
data Foo a = Bar Int a | Foo String | Baz a a
这声明了一个Foo a具有三个构造函数的类型:
Bar :: Int -> a -> Foo a
Foo :: String -> Foo a
Baz :: a -> a -> Foo a
基本上,构造函数名称后面的每个类型都是构造函数的参数。
- 因为 in
fmap :: (a-> b) -> f a -> f b,f a有种*,要写 Functor 的实例Flip,我们把它写在最后一个类型 in 上Flip。Akaf和a在某种程度上是“常数”,我们为 type 编写函子b。
这基本上是对的!你也可以说f有种* -> *。由于Flip具有 kind (* -> *) -> * -> * -> *,您需要为它提供两个类型参数(第一个* -> *和第二个*)以使其成为正确的类型。前两个参数在实例中变得固定(某种意义上是“常量”)。
我会这样写:...我知道这是完全错误的,但我不确定为什么。
您的实例完全错误的原因是您将类型与构造函数混淆了。(Flip x y z)将模式位置放在你所做的位置是没有意义的,因为构造函数 Flip只接受一个参数——记住,它的类型是Flip :: f b a -> Flip f a b! 所以你想写这样的东西:
instance Functor (Flip f a) where
   fmap f (Flip fxa) = ...
现在,你填写什么...?你有一个值fxa :: f x a,你有一个函数f :: x -> y,你需要产生一个类型的值f y a。老实说,我不知道该怎么做。毕竟,什么是typ 的值f x a?我们不知道是什么f?!
另外,为什么我们要
K带入 的 Functor 实例Flip?有人可以彻底解释提出这个解决方案的过程以及为什么它是正确的吗?
我们在上面看到我们不能Functor为任意的编写实例f,但我们可以做的是为特定的 f. 事实证明,这K正是一种f有效的方法。让我们试着让它工作:
instance Functor (Flip K a) where
  fmap f (Flip kxa) = ...
什么时候f是任意的,我们被困在这里,但现在我们知道了kxa :: K x a。请记住,生成类型值的唯一方法K x a是使用构造函数 K。因此,这个值kxa 一定是使用那个构造函数创建的,所以我们可以将它分解为:kxa ? K x'where x' :: x。让我们继续并将其放入我们的模式中:
  fmap f (Flip (K x')) = ...
现在我们可以进步了!我们需要产生一个类型的值Flip K a y。唔。产生类型值的唯一方法Flip是使用Flip构造函数,所以让我们从它开始:
  fmap f (Flip (K x')) = Flip ...
Fliptype 处的构造函数Flip K a y采用type的值K y a。产生其中之一的唯一方法是使用K构造函数,所以让我们添加:
  fmap f (Flip (K x')) = Flip (K ...)
Ktype 处的构造函数K y a接受一个type值y,所以我们需要在y这里提供一个 type 值。我们有一个值x' :: x和一个函数f :: x -> y。将第一个插入第二个为我们提供了我们需要的值:
  fmap f (Flip (K x')) = Flip (K (f x'))
只需重命名x'为b,您就拥有老师提供的代码。