【问题标题】:What functionality do you get for free with Functors or other type-classes?使用 Functor 或其他类型类可以免费获得哪些功能?
【发布时间】:2012-01-09 07:50:10
【问题描述】:

我读了一封article,上面写着:

为许多标准类型类 [Functors] 提供实例将立即为您提供许多几乎免费的功能

我的问题是:您免费获得的这个功能是什么(对于函子或其他类型类)?我知道仿函数的定义是什么,但是通过将某些东西定义为仿函数/其他类型类,我可以得到什么免费。除了更漂亮的语法之外的东西。理想情况下,这将是在仿函数/其他类型类上运行的通用且有用的函数。

我对免费意味着什么的想象(可能是错误的)是这种函数:TypeClass x => useful x y = ..

== 编辑/添加 ==

我想我主要是在询问更抽象(和令人难以置信)的类型类,比如this image 中的那些。对于像 Ord 这样不那么抽象的类,我的面向对象直觉可以理解。

【问题讨论】:

    标签: haskell typeclass functor


    【解决方案1】:

    函子很简单,可能不是最好的例子。让我们看看 Monads:

    • liftM - 如果某物是 Monad,它也是一个 Functor,其中 liftMfmap
    • >=><=<:你可以免费编写 a -> m b 函数,m 是你的 monad。
    • foldM, mapM, filterM... 你会得到一堆实用函数,它们可以泛化现有函数以使用你的 monad。
    • whenguard* 和unless——您还可以免费获得一些控制功能。
    • join -- 这实际上是定义 monad 的基础,但您不需要在 Haskell 中定义它,因为您已经定义了 >>=
    • 变形金刚——ErrorT 之类的。您可以免费(给予或接受)将错误处理绑定到新类型!

    基本上,只要将新类型设置为Monad 实例,就可以“提升”各种标准函数以使用新类型。将其设为 FunctorApplicative 也变得微不足道(但可惜不是自动的)。

    但是,这些都是更一般的想法的“症状”。您可以编写适用于 所有 monad 的有趣、重要的代码。您可能会发现为您的类型编写的一些函数(无论出于何种原因,它们在您的特定情况下都很有用)可以推广到所有 monad。现在,您可以突然将您的函数用于解析器、列表、可能和...

    * 正如 Daniel Fischer 乐于指出的那样,guard 需要 MonadPlus 而不是 Monad

    【讨论】:

    • guard 需要MonadPlus
    • 因为似乎只有少数这样的库函数,即使对于非常丰富的类型类的 monad,我认为这不太可能发生。 理论上您的代码可能会神奇地推广到所有 monad,但实际上如果它们存在,我会看到更多免费的 monad 有用函数。
    【解决方案2】:

    函子本身并不是很有趣,但它们是进入应用函子和Traversables的必要垫脚石。

    使应用函子有用的主要属性是您可以使用fmap 和应用运算符<*> 来“提升”任何数量的任何函数以使用应用值。 IE。您可以将任何a -> b -> c -> d 变成Applicative f => f a -> f b -> f c -> f d。您还可以查看Data.TraversableData.Foldable,它们包含几个涉及应用函子的通用函数。

    Alternative 是一个专门的应用函子,它支持在可能“失败”的备选方案之间进行选择(“空”的确切含义取决于应用实例)。应用解析器是一个实际示例,其中 somemany 的定义非常直观(例如,匹配某个模式零次或多次或一次或多次)。

    Monad 是最有趣和最有用的类型类之一,但其他答案已经很好地涵盖了它们。

    Monoid 是另一个既简单又立即有用的类型类。它基本上定义了一种将两条数据添加在一起的方法,然后为您提供了一个通用的concat 以及上述Foldable 模块中的功能,它还使您能够使用Writer monad 和数据类型。

    【讨论】:

      【解决方案3】:

      haskell 中有许多标准函数要求它们的参数实现一个或多个类型类。在您的代码中这样做可以让其他开发人员(或您自己)以他们已经熟悉的方式使用您的数据,而无需编写额外的函数。

      例如,实现 Ord 类型类将允许您使用 sort、min、max 等。否则,您将需要 sortBy 等。

      【讨论】:

        【解决方案4】:

        是的,这意味着实现类型类Foo 可以“免费”为您提供所有其他具有Foo 约束的函数。

        Functor 类型类在这方面并不太有趣,因为它没有给你很多东西。

        一个更好的例子是 monad 和 Control.Monad 模块中的函数。为您的类型定义了两个 Monad 函数 (>>=)return 后,您将获得另外 30 个左右的函数,然后可以在您的类型上使用。

        一些比较有用的包括:mapMsequenceforeverjoinfoldMfilterMreplicateMwhenunless和@987654@3 .这些总是出现在 Haskell 代码中。

        【讨论】:

          【解决方案5】:

          正如其他人所说,Functor 本身实际上并不能免费为您带来很多好处。基本上,类型类越高级或通用(意味着符合该描述的东西越多),那么您将获得的“免费”功能就越少。所以例如 Functor 和 Monoid 并没有为你提供太多,但 Monad 和 Arrow 免费为你提供了很多有用的功能。

          在 Haskell 中,为 Functor 和 Monoid 编写一个实例仍然是个好主意(如果您的数据类型确实是 functor 或 monoid),因为在编写函数时我们几乎总是尝试使用最通用的接口。如果您正在编写一个只使用fmap 对您的数据类型进行操作的新函数,那么没有理由人为将该函数限制为Monads 或Applicatives,因为它可能是以后对其他事情有用。

          【讨论】:

            【解决方案6】:

            如果您阅读“类型类和实例”的“接口和实现”,您的面向对象的直觉就会延续。如果您将新类型 C 设为标准类型类 B 的实例,那么您的类型将免费使用依赖于 B 的所有现有代码 A。

            正如其他人所说,当类型类类似于 Monad 时,免费赠品是许多库函数,例如 foldMwhen

            【讨论】:

              猜你喜欢
              • 2014-06-04
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-05-09
              • 2020-05-08
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多