【问题标题】:Why is the Functor instance for (,) mapping on the second value? [duplicate]为什么 (,) 的 Functor 实例映射在第二个值上? [复制]
【发布时间】:2018-06-01 12:47:33
【问题描述】:

在 Haskell 中,(,) 的 Functor 实例显然是

instance Functor (,) where
    fmap f (a,b) = (a,f b)

这导致了一个不直观的事实:

> fmap (const 5) [1, 2]
[5,5]
> fmap (const 5) (1, 2)
(1,5)

现在,在我看来,使用这个定义会更好:

instance Functor (,) where
    fmap f (a,b) = (f a,f b)

它会像这样工作:

> fmap (const 5) (1, 2)
(5,5)

为什么不是这样?

【问题讨论】:

  • 你如何定义fmap succ ("Hello!", 42)
  • 因为class Functor (a :: * -> *) where ...所以它需要一个类型参数,并且类型参数的顺序是data (,) a b = (a, b)
  • 您是否尝试过编写data MyTuple a b = MyTuple a b(以便您可以提供一个新实例),将您提议的实例转换为MyTuple,并查看编译器的内容?你得到的错误序列应该很有启发性。
  • 这只是因为函子是在单一类型上定义的,而元组包含多种类型。因此……只有其中一个可以生效。

标签: haskell tuples functor


【解决方案1】:

实例实际上不是你说的instance Functor (,)。那可不是善意的:

Prelude> :k Functor
Functor :: (* -> *) -> Constraint
Prelude> :k (,)
(,) :: * -> * -> *

即,(,) 采用两个类型参数(两个元组字段的类型)来构造一个元组类型,但 Functor 类实际上是用于仅采用 一个的类型构造函数> 论据,例如

Prelude> :k []
[] :: * -> *
Prelude> :k IO
IO :: * -> *

那么为什么会有一个仿函数实例呢?坦率地说,我认为这是应该定义的实例之一,正是因为元组不对称令人困惑。然而,它可以真正被定义,并且只有一种方法可以做到,所以标准库的这种选择当然不是不合理。诀窍是currying:您可以将(,) 构造函数部分应用于任何固定的左字段类型,然后为您提供一个单参数类型的构造函数。例如

Prelude> :k (,) Int
(,) Int :: * -> *

这样你就可以拥有

instance Functor ((,) Int)

显然它不依赖于左字段的具体类型,所以你也可以制作它

instance Functor ((,) a)

在值级别的 Haskell 中,这部分会写成

instance Functor (a,)

与术语级别不同,部分应用对最左边的参数起作用((,b) 部分实际上是\a -> (a,b) 的糖,但在Haskell),所以instance Functor ((,) a) 是这里唯一可能的实例。

要获得您要求的行为,即应用于两个/所有字段的函数,您需要两个字段实际上具有相同的类型。即,您需要一个类型构造函数,它只有一个参数开头,并且只将该类型两次用于其 value 构造函数的字段。具有该行为的标准类型是 V2

【讨论】:

  • 当您开始使用它的 ApplicativeMonad 实例时,我觉得这个特定的 Functor 实例开始变得更有意义(尤其是关于它的实用性)(这样,对于@MarkNeu,稍后可能值得记住)。
【解决方案2】:

此行为可从 Product 函子获得:

Data.Functor.Product Data.Functor.Identity> fmap (+1) (Pair 5 6) :: Product Identity Identity Integer
Pair (Identity 6) (Identity 7)

如您所见,Product(,) 之间的主要区别在于Pair 的两个元素具有相同的叶类型(在本例中为Integer)。 (相关:请注意,在上面的类型中,Integer 只被提及一次,而在 (5,6) 的类型中,Integer 被提及两次。)因为(,) 可能包含完全不相关的类型,不能保证您可以以良好类型的方式将单个函数应用于两个部分。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-11-06
    • 2020-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-11-28
    • 2022-12-07
    • 1970-01-01
    相关资源
    最近更新 更多