简体   繁体   English

monads和ZipList以外的应用函子?

[英]Applicative functors other than monads and ZipList?

Two well-known examples of applicatives are monads and ziplists. 两个着名的应用实例是单子和拉链。 Are there any other examples? 还有其他例子吗?

From Time flies like an applicative functor by Conor McBride: 来自时间的飞行像康纳麦克布莱德的应用函子

Structure cops will note that De is another example of an applicative functor which is not a monad — join would bring things from the far future to the near future, and that had better not be possible. 结构警察会注意到De是另一个不是monad的应用函子的例子 - join将把事物从远期带到不久的将来,并且最好不可能。 However, where applicative functors in general only pull through traversable functors (containers with finitely many elements), De pulls through all containers. 然而,在一般情况下,应用仿函数只能穿过可穿越的仿函数(具有有限多个元素的容器), De拉过所有容器。 So it's a bit special. 所以它有点特别。 I wonder what it is. 我不知道它是什么。

and

The De functor represents a fixed delay, rather than an arbitrary one. De仿函数表示固定延迟,而不是任意延迟。 I'm dividing time into discrete slices. 我把时间分成不连续的切片。 De x is the type of an x due at the next slice. De x是下一个切片的x类型。 De (De x) is thus the type of an x due in two slices' time, and you can't make it turn up any sooner! De (De x)因此是两片时间内x的类型,你不能让它更快出现!

Read the whole post. 阅读整篇文章。 To answer the immediate question, the author's conclusion is 为了回答当前的问题,作者的结论是

Don't Look! 别看!

OK, here's the implementation. 好的,这是实施。 It's a con. 这是骗局。

 newtype De x = De x deriving Show -- ssh, don't tell! instance Functor De where fmap f (De x) = De (fx) instance Applicative De where pure = De De f <*> De s = De (fs) fix :: (De x -> x) -> x fix f = f (De (fix f)) 

I recently defined an Applicative instance for a newtype on top of (,,,) , a "quad". 我最近在(,,,) ,“quad”之上为newtype定义了一个Applicative实例。 (The standard library defines an instance for (,) , but not (,,,) . That's OK, as the standard implementation has different semantics than what I was after.) (标准库为(,)而不是(,,,)定义了一个实例。没关系,因为标准实现的语义与我之后的语义不同。)

The background is; 背景是; I am parsing some old data, and the date format in the data is ambiguous. 我正在解析一些旧数据,并且数据中的日期格式不明确。 Each date in the data can be parsed into four possibilities, stored in the quad. 数据中的每个日期都可以解析为四种可能性,存储在四边形中。 I then want to validate each date in the quad to eliminate semantically invalid dates. 然后,我想验证四元组中的每个日期,以消除语义无效的日期。 (There are no months with 32 days, there is no month 34, there is no 5th quarter, etc.) Finally, I want to take each date in the dataset, and reduce the entire set to a quad representing which date formats are valid for the entire set. (没有月份有32天,没有月份34,没有第5季度等等)最后,我想在数据集中取每个日期,并将整个集合缩减为表示哪些日期格式有效的四元组整套。 Then, I choose the best format out of those options, and assume that's what the date format of the dataset is. 然后,我从这些选项中选择最佳格式,并假设这是数据集的日期格式。

This entire operation is very easy to express as applicative operations on the quad structure. 整个操作很容易表达为四元结构的应用操作。

Here's the basic shape of the code: 这是代码的基本形状:

My new type: 我的新类型:

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)

Some prerequisite "pure" functions: 一些先决条件“纯”功能:

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

So once we have the quad of parsed dates (from parseDateInt ), we need to validate them: 因此,一旦我们获得了解析日期的四元组(来自parseDateInt ),我们需要验证它们:

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

(This is only a Functor so far, but you could also write (pure validateDate <*>) . (到目前为止,这只是一个Functor,但您也可以编写(pure validateDate <*>)

It's also worth noting the symmetry between validation of a single element, and validating each element of the set -- to validate one, you might write validateDate $ date ; 同样值得注意的是单个元素验证与验证集合中每个元素之间的对称性 - 验证一个元素,你可以编写validateDate $ date ; to validate a set, you write validateDate <$> dates . 要验证集合,请编写validateDate <$> dates This is why fmap is written as <$> , it's function application to a functor.) 这就是为什么fmap被写为<$> ,它是函数应用程序的一个函数。)

The step after this is to take a set of valid parses and fold that into a final result: 此后的步骤是获取一组有效的解析并将其折叠成最终结果:

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

So now you can go from the [Int] in the data file to a DQ Bool representing the possibly-valid date representations for a dataset. 所以现在你可以从数据文件中的[Int]转到表示数据集可能有效的日期表示的DQ Bool (And from there, associate each data point with a real date object, instead of the flaky Int that was supplied.) (并从那里,将每个数据点与实际日期对象相关联,而不是提供的片状Int。)

So anyway, this post has gotten a bit long, but the idea is that an Applicative instance allowed me to solve my problem in about 3 lines of code. 所以无论如何,这篇文章已经有点长了,但是想法是一个Applicative实例允许我用大约3行代码解决我的问题。 My problem domain was repeatedly applying functions to data in a container, which is what an Applicative functor does. 我的问题域是重复将函数应用于容器中的数据,这是Applicative仿函数所做的。 There is no join operation on this data, so a Monad instance would not make much sense. 这个数据没有join操作,因此Monad实例没有多大意义。

Conal Elliott writes about signal processors and how they're applicatives . Conal Elliott撰写有关信号处理器以及它们如何应用的文章 Those are similar to ZipList in nature, where each respective pair of items in the two "containers" gets combined. 它们本质上类似于ZipList ,其中两个“容器”中的每个相应的项目对被组合。

I've been using this concept a lot in an unfinished yet cute game I made ( cabal install DefendTheKing to check it out). 我在一个未完成但又可爱的游戏中一直使用这个概念( cabal install DefendTheKing来检查它)。

Code snippet/example of Applicative-style usage: 代码段/应用风格用法示例:

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

Formlets are an abstraction over HTML forms described in terms of composing applicatives. Formlets是对HTML表单的抽象,这些HTML表单是根据编写应用程序而描述的。 A formlet applicative is the result of composing a name generating applicative (to generate form elements names), a XML writer applicative (to generate HTML), and an environment applicative (to supply the submitted form values). formlet applicative是组合生成applicative的名称(生成表单元素名称),XML编写器应用程序(生成HTML)和环境应用程序(提供提交的表单值)的结果。

Formlets can be extended by composing additional applicatives, for example to implement validation. 可以通过组合其他应用程序来扩展Formlet,例如以实现验证。

Cooper, Wadler et al show in the papers that formlets cannot be represented as monads. Cooper,Wadler等人在论文中表明,小分子不能表示为monad。

Formlets have been implemented in Haskell, here is the package . Formlet已在Haskell中实现, 这是包

Swierstra and Duponcheel defined an efficient style of parser, this parser was pretty much the early poster child for Arrows, but it doesn't need anything from Arrow that it can't get from Applicative. Swierstra和Duponcheel定义了一种高效的解析器样式,这个解析器几乎是Arrows的早期版本,但是它不需要来自Arrow的任何东西,它无法从Applicative获得。 However, Applicatives hadn't been coined at the time. 但是,申请人当时并没有被创造出来。

Effectively it computes 'FIRST' sets for an LL(1) parser and uses that to do smarter branch selection. 实际上,它为LL(1)解析器计算'FIRST'集,并使用它来进行更智能的分支选择。 However, you can't compute these sets when you work monadically. 但是,当您单独工作时,无法计算这些集。

This is perhaps not a terribly fair example, because the Swierstra/Duponcheel parser admits a blending of static and dynamic parsers, and it is only the static parser that is limited to being applicative. 这可能不是一个非常公平的例子,因为Swierstra / Duponcheel解析器允许混合静态和动态解析器​​,并且只有静态解析器才限于应用。

With observable sharing you can carry their parser design farther and also compute 'FOLLOW' sets (as long as you are careful to not build an infinite context free grammar.). 通过可观察共享,您可以进一步进行解析器设计并计算“FOLLOW”集(只要您小心不构建无限上下文无关语法。)。 This yields nice asymptotic guarantees for parsing context free grammars, which are not available to you when parsing using monadic (context sensitive) parser designs. 这为解析上下文无关语法提供了很好的渐近保证,这在使用monadic(上下文敏感)解析器设计进行语法分析时是不可用的。

Also interesting perhaps, is to consider the structures for which the <*> of applicative is available, but not the pure. 也许有趣的是,要考虑应用<*>的结构,而不是纯粹的结构。 Many comonads admit a (<*>)-like definition, which respects the structure of the comonad, but don't have a reasonable definition for 'pure'. 许多comonads承认一个(<*>) - 类似的定义,它尊重comonad的结构,但对'pure'没有合理的定义。 My semigroupoids package and the myriad packages that depend upon it explore this idea further. 我的半群包和依赖它的无数包都会进一步探索这个想法。

I believe arrows are applicative functors. 我相信箭是适用的算符。 There is certainly a WrapArrow type in Control.Applicative. 在Control.Applicative中肯定有一个WrapArrow类型。

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM