gpt4 book ai didi

haskell - 让 Haskell 仿函数沉入其中。

转载 作者:行者123 更新时间:2023-12-02 09:50:33 25 4
gpt4 key购买 nike

Learn You a Haskell有一个关于仿函数的例子。我可以阅读 LYAH 和文字,并弄清楚应该发生什么——但我知道的内容还不够多,无法写出这样的东西。我经常在 Haskell 中发现这个问题。

instance Functor (Either a) where  
fmap f (Right x) = Right (f x)
fmap f (Left x) = Left x

但是,我很困惑..为什么这不完整
instance Functor (Either a) where  
fmap f (Right x) = Right (x)
fmap f (Left x) = Left (f x)

如果 f没有在顶级定义中使用,那么还有什么限制 x以至于不能满足 Left

最佳答案

这是仿函数类:

class Functor f where
fmap :: (a -> b) -> f a -> f b

请注意,“f”本身是一个类型构造函数,因为它应用于 fmap 行中的类型变量。这里有一些例子可以说明这一点:

类型构造函数:
IO
Maybe
Either String

类型:
IO Char
Maybe a
Either String String

“Maybe a”是具有一个类型构造函数(“Maybe”)和一个类型变量(“a”)的类型。它还不是具体的东西,但它可用于多态函数的类型签名。

"Either"是一个接受两个类型参数的类型构造函数,所以即使你应用了一个(例如 Either String 它仍然是一个类型构造函数,因为它可以接受另一个类型参数。

这一点是:当你定义一个 Functor例如, 类型构造函数 f不能变。 这是因为它由相同的变量 f 表示。 , 作为 fmap 的参数和结果.唯一允许更改的类型是应用于 f 的类型。构造函数。

当你写 instance Functor (Either c) , Either c填写为 f fmap 的声明中无处不在.这为这个实例提供了以下类型的 fmap:
fmap :: (a -> b) -> (Either c) a -> (Either c) b

定义为 Either ,获得此类型的唯一有用方法是应用 Right函数的值(value)。请记住,“Either”有两个可能具有不同类型的值。这里 Left value 的类型为“c”,因此您不能将其应用于函数(需要一个“a”)[1],并且结果也不正确,因为您将留下 Either b a ,与类定义不匹配。

在将“f”替换为“Either c”以获得上述带有“Either c”实例的fmap的类型签名之后,接下来是编写实现。有两种情况需要考虑,左派和右派。类型签名告诉我们左侧的类型“c”不能更改。我们也没有任何方法可以更改该值,因为我们不知道它实际上是什么类型。我们所能做的就是别管它:
fmap f (Left rval) = Left rval

对于右侧,类型签名表明我们必须将类型为“a”的值更改为类型为“b”的值。第一个参数是一个函数来做这件事,所以我们使用这个函数和输入值来获得新的输出。将两者放在一起给出了完整的定义
instance Functor (Either c) where
fmap f (Right rval) = Right (f rval)
fmap f (Left lval) = Left lval

这里有一个更一般的原则在起作用,这就是为什么编写一个调整左侧的 Functor 实例是不可能的,至少在 Prelude 定义中是不可能的。从上面复制一些代码:
class Functor f where
fmap :: (a -> b) -> f a -> f b

instance Functor (Either c) where ...

即使我们在实例定义中有一个类型变量“c”,我们也不能在任何类方法中使用它,因为它没有在类定义中提及。所以不能写
leftMap :: (c -> d) -> Either c a -> Either d a
leftMap mapfunc (Left x) = Left (mapfunc x)
leftMap mapfunc (Right x) = Right x

instance Functor (Either c) where
--fmap :: (c -> d) -> Either c a -> Either d a
fmap = leftMap

leftMap 和 fmap 的结果现在是 (Either d) a . (Either c)已更改为 (Either d) ,但这是不允许的,因为没有办法在 Functor 类中表达它。为了表达这一点,您需要一个具有两个类型变量的类,例如
class BiFunctor f where
lMap :: (a -> b) -> f a c -> f b c
rMap :: (c -> d) -> f a c -> f a d
biMap :: (a -> b) -> (c -> d) -> f a c -> f b d

在这个类中,由于左右类型变量都在范围内,因此可以编写在任一(或两侧)操作的方法。
instance BiFunctor Either where
lMap = leftMap
rMap = rightMap --the same as the standard fmap definition
biMap fl fr e = rMap fr (lMap fl e)

尽管在实践中人们通常只为 BiFunctor 类编写“biMap”,如果需要左映射或右映射,则将“id”用于其他函数。

[1] 更准确地说,Left 值的类型为“c”,该函数需要一个“a”,但类型检查器无法统一这些类型,因为“c”类型不在类定义的范围内。

关于haskell - 让 Haskell 仿函数沉入其中。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3155469/

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