【问题标题】:Why is `pure` only required for Applicative and not already for Functor? [duplicate]为什么只有 Applicative 需要 `pure` 而 Functor 不需要? [复制]
【发布时间】:2015-10-30 16:57:17
【问题描述】:

阅读this Wikibook about Haskell and Category Theory basics,我了解了Functors:

函子本质上是类别之间的转换,所以给定 类别 C 和 D,函子 F : C -> D

将 C 中的任何对象 A 映射到 D 中的 F(A)。

将 C 中的态射 f : A -> B 映射到 D 中的 F(f) : F(A) -> F(B)。

...听起来不错。稍后提供示例:

让我们也有一个示例实例:

instance Functor Maybe where
  fmap f (Just x) = Just (f x)
  fmap _ Nothing  = Nothing

这是关键部分:类型构造函数 Maybe 将任何类型 T 转换为 新类型,Maybe T。此外,仅限于 Maybe 类型的 fmap 需要一个 函数 a -> b 到函数 Maybe a -> Maybe b。但就是这样!我们已经 定义了两个部分,将 Hask 中的对象转换为 另一个类别(Maybe 上定义的 Maybe 类型和函数) 类型),以及将 Hask 中的态射转换为 这个类别。所以 Maybe 是一个函子。

我了解fmap 的定义是关键。我对“类型构造函数 Maybe”如何提供第一部分感到困惑。我宁愿期待像pure 这样的东西。

如果我做对了,Maybe 宁可将C 映射到D。 (因此是类别级别的态射,这可能是 Functor 的要求)

我想你可以这样改写我的问题:是否有一个 Functor 没有明显的 pure 实现?

【问题讨论】:

  • 感谢所有有用的答案。我选择了最详细的一个是“正确的”。
  • 一个不承认pure 的简单Functordata Void a。该实例看起来像instance Functor Void where { fmap f x = case x of {} }。 (我没有把这个作为答案,因为我认为这个例子并不是特别有启发性,即使它回答了你在正文中实际提出的唯一问题。)
  • @DanielWagner 我认为这取决于不承认pureonly Functor 的同构:如果你有any 值@ 987654335@ 在Functor 中可以定义pure x = x <$ v。我认为pure 的每个选择也是这种形式。当然,这通常不是很独特。
  • "将 Hask 中的对象带到另一个类别中的对象(Maybe 类型和在 Maybe 类型上定义的函数)" 我认为您混淆了 codomain 和图像。这里的codomain和domain一样,都是Hask,所以我们说的是endofunctor。 Maybe 下 Hask 的 image 是 codomain 的 subset -- 所有 Maybe 类型。你可以很容易地说服自己,Maybe 不会让你脱离 Hask,因为你可以多次应用 Maybe —— Maybe (Mabe a) 等等——内在的 Maybe 仍然在 Maybe 的领域。
  • @BartoszMilewski 你说得对,那是我的困惑。下面的答案已经澄清了这一点。我应该纠正我的问题吗(对我来说似乎没有必要)?

标签: haskell functor category-theory


【解决方案1】:

我认为您对类型和值感到困惑。下面是函子的定义:

CDcategories。从 CD函子 F 是一个映射:

  • 将每个对象 X ∈ C 关联到一个对象 F(X) ∈ D

  • 关联到每个态射 f : X → Y ∈ C 一个态射 F(f) : F(X) → F(Y) ∈ D 使得以下条件成立:

    • F(id : X → X) = id : F(X) → F(X) 对于每个对象 X ∈ C
    • F(g ∘ f) = F(g) ∘ F(f) 对于所有态射 f : X → Yg : Y → Z.

类别由对象和对象之间的态射组成。

Haskell 中的所有代码都是 Hask 的一部分,Haskell 类别。在 Hask 中:

  1. 类型就是对象。
  2. 函数是类型之间的态射。

因此,Haskell 中的所有 Functor 实例都是从 Hask 到 Hask 的函子(即它们是内函子)。

更严格地说,对于 Haskell 中的所有 Functor 实例:

  1. C = Hask
  2. D = Hask

现在,每个函子 F 是一个映射,它与每个对象 X ∈ C 关联一个对象 F(X) ∈ D

  1. 请注意,XF(X) 分别是 CD 的对象。
  2. 由于CD都是Hask,所以XF(X) 是类型而不是值。
  3. 因此,F : Type → Type 或在 Haskell 中 f : * -> *

确实,这正是 Haskell 中 Functor 类型类的定义方式:

class Functor (f : * -> *) where
    fmap :: (x -> y) -> (f x -> f y)

这里,fmap 是函子的第二部分。这是一个从值到值的函数。但是,Functor 本身是一个类型构造函数(即从类型到类型的映射)。这就是Maybe 是函子而[] 是函子但Maybe Int[Int] 不是函子的原因。

请注意,pure 不是函子定义的第一部分,因为它是从 X 实例到 F(X) 实例的映射(即它是一个从值到值的函数)。但是,我们需要从 XF(X) 的映射(即从类型到类型的映射)。

【讨论】:

    【解决方案2】:

    如果我做对了,Maybe 宁可将C 映射到D。 (因此是类别级别的态射,这可能是 Functor 的要求)

    不是真的,因为 CD 有类别,而不是 Haskell 类型。 Functor(即类型类的实例,与一般的函子相反)是从 Hask 类别(Haskell 类型和函数的类别)到 的映射Hask 本身;也就是说,CD 在这种情况下都是 Hask。 Wikibook 章节在 Hask 上的 Functors 部分提到了这一点。在您的示例中,Maybe 类型构造函数通过将某些类型 aHask 中的对象)转换为类型 Maybe a 中的另一个对象)来提供映射的第一部分哈斯克)。

    我想你可以这样改写我的问题:是否有一个 Functor 没有明显的 pure 实现?

    一个例子是Functor(,) afmap 很容易写——\f (x, y) -> (x, f y)——但pure(<*>) 需要Monoid 约束a,否则将无法处理额外的a 值。有关更多讨论和其他示例,请参阅Good examples of Not a Functor/Functor/Applicative/Monad?

    【讨论】:

      【解决方案3】:

      我会说Applicative 的实例有点成为Either 的延伸(如果我有一个Bifunctor 的实例就可以了,但另一方面将它用作Monad 是方便),并且(恕我直言)不适合以下情况:

      data ABC a = A a | B a | C a
      

      所有 A、B、C 都“同样可以”。由于没有明显的选择应该用于pure,因此根本不应该提供它。不过,拥有fmap 仍然很好。

      【讨论】:

      • 有道理...与实现 pure 相关的任意性被推迟到有人实现 Applicative 之前(此时必须做出选择)。
      • @ruben.moor 当你决定了你想如何在你的应用程序中实现<*> 时,pure 不再是任意的:它受到应用程序法律的限制。实现一个完全任意的pure 作为 Functor 的一部分,您不必真正考虑 pure 与其他任何东西的交互方式,可能会很容易意外地编写一个不适用于 Applicative(或 Monad)的pure )。
      【解决方案4】:

      分类 Hask 的类型为对象,函数为箭头,因此 Functor 实例提供的对象映射必须将类型映射到类型。

      fmap 映射箭头,即将函子 f 的函数 a -> b 映射到函数 f a -> f b。 Functor 类型构造函数是对象的映射,即类型之间的映射。

      例如,Maybe 类型构造函数将类型 t 映射到类型 Maybe t,例如StringMaybe String

      相比之下,pure 将某些底层类型的值映射到相应应用类型的值,例如"abc" 和 (Just "abc") 分别是 StringMaybe String 的值。

      【讨论】:

      • 您是否同意 Wikibook 文章将类别态射与纯态射混淆,其中说:将 C 中的任何对象 A 映射到 D 中的 F(A)?
      • 维基书上的文章是正确的。 Functor f 中的fHask 类别中的对象映射到Hask 类别中的对象。请注意,Haskell Functor 严格来说是一个内函子——它的域和共域都必须是 Hask。然后,函数fmap 将Hask 中的态射(a -> b 类型的函数)映射到Hask 中的态射,特别是态射f a -> f b。在文章中,函子的类型为Hask ~> Hask。但请注意,此箭头不是函数箭头 - 函数箭头将 types 转换为 types,而不是将类别转换为类别。
      • @user2407038 确实,现在我明白了。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-18
      • 2018-07-30
      • 2011-06-18
      • 2021-04-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多