5

考虑类型a -> b -> c的函数和应用值a1, a2 :: (Applicative f) => f a

我希望构造一个函数,该函数可应用于 type 函数a -> b -> c以获得 type 的值Applicative f :: f c。我可以通过以下方式做到这一点:

g :: (Applicative f) => (a -> b -> c) -> f c
g = \f -> f <$> a1 <*> a2

(显式 lambda 是经过深思熟虑的,因为我正在考虑在任何级别构建此函数,而不仅仅是顶层)。

如果我尝试以g无点风格写作:

g = (<$> a1 <*> a2)

我收到以下编译错误:

The operator `<$>' [infixl 4] of a section
    must have lower precedence than that of the operand,
      namely `<*>' [infixl 4]
    in the section: `<$> gen1 <*> gen2'

可以编写这个无点实现:

g = flip (flip liftA2 a1) a2

但我觉得这不太可读,重构基于函数的中缀实现更简单,例如,添加另一个参数,而不是将上面的内容更改为 use liftA3

一个人可以写出一系列的作品:

g = (<*> a2) . (<$> a1)

这实现了无点样式,并且添加参数很简单 - 但它们被添加到左侧而不是添加到右侧,因此您失去了与函数类型的对应关系(a -> b -> c)。此外,与在第一个实现中仅使用 lambda 相比,使用更多参数最终会得到更长的表达式。

那么,是否有很好、简洁的方式来编写我想要的部分,还是我坚持使用 lambda?

4

2 回答 2

8

<*>对 的结果进行运算<$>,因此:

g = (<*> a2) . (<$> a1)
于 2015-06-10T06:09:26.703 回答
6

我真的不相信 pointfree 可以比在这里使用显式参数更好,但还有一些想法:

  • 您可以使用中flip缀:

    g = liftA2 `flip` a1 `flip` a2
    
  • 您可以使用>>>from Control.Category,它被.翻转:

    g = (<$> a1) >>> (<*> a2)
    
于 2015-06-10T08:32:39.510 回答