gpt4 book ai didi

haskell - 定义你自己的 Functor

转载 作者:行者123 更新时间:2023-12-01 12:48:39 29 4
gpt4 key购买 nike

我一直在努力理解 Haskell 中的 Functor 是什么,为此我想要一个没有任何其他属性的 Functor 示例。

我想出的工作示例是

data MyFunctor a b = MyFunctor a b deriving Show
instance Functor (MyFunctor a) where
fmap g (MyFunctor a b) = MyFunctor a $ g (b)

我猜这是一个半实用的 Functor,因为可以在对右值进行操作时安全地存储左值。然后我想在操作之前将左值替换为右值。这样……

Main> fmap (+2) MyFunctor 2 5
MyFunctor 5 7

然而,更改实例声明来执行此操作会产生错误。

data MyFunctor a b = MyFunctor a b deriving Show
instance Functor (MyFunctor a) where
fmap g (MyFunctor a b) = MyFunctor b $ g (b)

我不明白,或者不知道要搜索什么来找到足够相似的问题来帮助我。

C:\Haskell\func.hs:3:28: error:
* Couldn't match type `a1' with `a'
`a1' is a rigid type variable bound by
the type signature for:
fmap :: forall a1 b. (a1 -> b) -> MyFunctor a a1 -> MyFunctor a b
at C:\Haskell\func.hs:3:3
`a' is a rigid type variable bound by
the instance declaration at C:\Haskell\func.hs:2:10
Expected type: MyFunctor a b
Actual type: MyFunctor a1 b
* In the expression: MyFunctor b $ g (b)
In an equation for `fmap':
fmap g (MyFunctor a b) = MyFunctor b $ g (b)
In the instance declaration for `Functor (MyFunctor a)'
* Relevant bindings include
b :: a1 (bound at C:\Haskell\func.hs:3:23)
a :: a (bound at C:\Haskell\func.hs:3:21)
g :: a1 -> b (bound at C:\Haskell\func.hs:3:8)
fmap :: (a1 -> b) -> MyFunctor a a1 -> MyFunctor a b
(bound at C:\Haskell\func.hs:3:3)

最佳答案

I then want to have the left value be replace with the right value before the operation.

对于 Functor 来说,这是非法的:GHC 正确地告诉你类型不成立。特别是,MyFunctor 值的左侧部分可能与右侧部分的类型不同,如 MyFunctor 5 "hello" 中所示。并且由于 fmap 必须仅对您的类型的最后一个类型参数进行操作,因此它必须单独保留第一部分。让我们看一个更具体的例子。

回想一下fmap的类型是

fmap :: Functor f => (a -> b) -> f a -> f b

假设你有一个你想要fmap的对象:

obj :: MyFunctor Int String

那么,f 的类型必须是什么才能调用 fmap f obj?为了统一涉及的类型,我们必须有

f :: (String -> a)

fmap f obj :: MyFunctor Int a

因此您可以看到,不可能用第二个 String 字段的先前值“替换”第一个 Int 字段:那个地方唯一允许的是之前存在的 Int!

现在,您可能会想象,如果您更改 MyFunctor 定义,使两个字段具有相同的类型,就可以使类型生效:

data MyFunctor a = MyFunctor a a

-- Also illegal
instance Functor MyFunctor where
fmap f (MyFunctor a b) = MyFunctor b (f b)

但是你也不能这样做,因为 bf b 可能是不同的类型,调用者可以选择 f > 使用,因此您的 fmap 实现可能不会假设它们是相同的。

事实上,对于任何给定的数据类型,最多有一个 Functor 的合法定义:如果你找到一个合法的,你可以确定任何其他定义都是非法的:要么类型不匹配,否则它将违反两个 Functor 定律之一:

fmap id == id
fmap f . fmap g == fmap (f . g)

如何在仍然保持类型排队的情况下违反其中一条法律?通过对不属于被 fmap 覆盖的结构的一部分的结构进行操作。例如,经常有人像这样写一个(糟糕的!)仿函数:

data Counter a = Counter Int a

instance Functor Counter where
fmap f (Counter n x) = Counter (n + 1) (f x)

但这违反了两个 Functor 定律,因为它允许您计算 fmap 被调用了多少次,这应该是一个没有公开的细节。

fmap id (Counter 0 0) == Counter 1 0
(fmap tail . fmap tail) /= fmap (tail . tail)

关于haskell - 定义你自己的 Functor,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44808885/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com