monads和ZipList以外的应用函子?

时间:2010-01-22 21:06:47

标签: haskell functional-programming

两个众所周知的应用实例是monad和ziplists。还有其他例子吗?

7 个答案:

答案 0 :(得分:11)

来自Conor McBride的Time flies like an applicative functor

  

结构警察会注意到De是另一个不是monad的应用函子的例子 - join将把事物从遥远的未来带到不久的将来,而且最好不可能。然而,在一般情况下,应用函子只能通过可遍历的函子(具有有限多个元素的容器),De会拉过所有容器。所以它有点特别。我不知道它是什么。

  

De仿函数表示固定延迟,而不是任意延迟。我把时间分成不连续的切片。 De x是下一个切片的x类型。 De (De x)因此是x在两片时间内到期的类型,你不能让它更快出现!

阅读整篇文章。要回答当前的问题,作者的结论是

  

不要看!

     

好的,这是实施。这是一个骗局。

newtype De x = De x deriving Show -- ssh, don't tell!

instance Functor De where
  fmap f (De x) = De (f x)

instance Applicative De where
  pure = De
  De f <*> De s = De (f s)

fix :: (De x -> x) -> x
fix f = f (De (fix f))

答案 1 :(得分:9)

我最近在(,,,)之上定义了一个新类型的Applicative实例,一个“四元组”。 (标准库定义了(,)的实例,但不是(,,,)。这没关系,因为标准实现的语义与我之后的语义不同。)

背景是;我正在解析一些旧数据,并且数据中的日期格式不明确。数据中的每个日期都可以解析为四种可能性,存储在四边形中。然后,我想验证四元组中的每个日期,以消除语义无效的日期。 (没有月份有32天,没有月份34,没有第5季度等等)最后,我想在数据集中取每个日期,并将整个集合缩减为表示哪些日期格式有效的四元组整套。然后,我从这些选项中选择最佳格式,并假设这是数据集的日期格式。

这整个操作很容易表达为四元结构的应用操作。

以下是代码的基本形状:

我的新类型:

newtype DQ a = DQ (a, a, a, a) -- date quad
             deriving ...

instance Functor DQ where
   g `fmap` f = pure g <*> f

instance Applicative DQ where
   pure x  = DQ (x, x, x, x)
   DQ (g, h, i, j) <*> DQ (a, b, c, d) = DQ (g a, h b, i c, j d)

一些先决条件“纯粹”功能:

parseDateInt :: Int -> DQ Date
validateDate :: Date -> Bool
extractBestDate :: DQ Date -> DQ Bool -> Date

因此,一旦我们获得了解析日期的四元组(来自parseDateInt),我们需要验证它们:

validateDates :: DQ Date -> DQ Bool
validateDates = (validateDate <$>)

(到目前为止,这只是一个Functor,但你也可以写 (pure validateDate <*>)

值得注意的是单个验证之间的对称性 元素,并验证集合中的每个元素 - 验证一个,你可能会写 validateDate $ date;要写一套验证集 validateDate <$> dates。这就是fmap被写为<$>的原因,它是函数应用程序的一个函数。)

此后的步骤是采取一组有效的解析并折叠它 最后的结果:

intuitDateType :: [DQ Bool] -> DQ Bool
intuitDateType dates = foldl1 (liftA2 (&&)) dates

现在您可以从数据文件中的[Int]转到DQ Bool 表示数据集的可能有效的日期表示。 (并从那里,将每个数据点与实际日期对象相关联, 而不是提供的片状Int。)

所以无论如何,这篇文章已经有点长了,但是这个想法是一个 应用实例允许我在大约3行中解决我的问题 代码我的问题域是重复将函数应用于数据 容器,这是一个Applicative仿函数。对这些数据没有join操作,因此Monad实例没有多大意义。

答案 2 :(得分:5)

Conal Elliott writes about signal processors and how they're applicatives。它们本质上与ZipList相似,两个“容器”中的每一对项目都被合并。

我在一个未完成但又很可爱的游戏中一直使用这个概念(cabal install DefendTheKing来检查它)。

代码段/应用样式用法示例:

draw font
<$> lstP gABoard
<*> lstP gASelection
<*> mouseMotion
<*> lstP gASide
<*> lstP gAGameIteration

答案 3 :(得分:4)

Formlets是对构成应用程序的HTML表单的抽象。 formlet applicative是组合生成applicative的名称(生成表单元素名称),XML编写器应用程序(生成HTML)和环境应用程序(提供提交的表单值)的结果。

可以通过编写其他应用程序来扩展Formlet,例如实现验证。

Cooper,Wadler等人在论文中表明,小分析不能表示为monad。

在Haskell中实现了Formlets,here is the package

答案 4 :(得分:4)

Swierstra和Duponcheel定义了一种高效的解析器样式,这个解析器几乎是Arrows的早期版本,但是它不需要来自Arrow的任何东西,它无法从Applicative获得。但是,申请人当时并没有被创造出来。

实际上,它为LL(1)解析器计算'FIRST'集,并使用它来进行更智能的分支选择。但是,当您单独工作时,无法计算这些集。

这可能不是一个非常公平的例子,因为Swierstra / Duponcheel解析器允许混合使用静态和动态解析器​​,并且只有静态解析器才限于应用。

通过可观察共享,您可以进一步进行解析器设计并计算“FOLLOW”集(只要您小心不构建无限上下文无关语法。)。这为解析上下文无关语法提供了很好的渐近保证,在使用monadic(上下文敏感)解析器设计进行语法分析时,这些语法是不可用的。

也许有趣的是,要考虑&lt; *&gt;的结构。适用的是,但不是纯粹的。许多comonads承认一个(&lt; *&gt;)类似的定义,它尊重comonad的结构,但对'pure'没有合理的定义。我的semigroupoids包和依赖它的无数包进一步探索了这个想法。

答案 5 :(得分:1)

我相信箭是适用的算符。在Control.Applicative中肯定有一个WrapArrow类型。

答案 6 :(得分:1)

McBride和Paterson http://www.soi.city.ac.uk/~ross/papers/Applicative.pdf表明,monoid可以被视为一个应用函子,但一般情况下它不是monad。