4

无点函数可以返回元组吗?例如,以下是否可以用 pointfree 样式编写(其中 f1、f2 和 f3 已定义):

(\t -> (f1 t, f2 t, f3 t))

在这种情况下,我的 f1、f2 和 f3 是 quot、mod、* 和一些整数的组合。

(\f1,f2,f3 -> (\t -> (f1 t, f2 t, f3 t)))

是一个更一般的情况,并且等价于

(\f1,f2,f3,t -> (f1 t, f2 t, f3 t))

命名函数是可以的,但我的例子是匿名的。(命名示例如下)

f x = (f1 x, f2 x, f3 x)
f f1 f2 f3 x = (f1 x, f2 x, f3 x)

编辑:我只是好奇,我不会这样做。

4

5 回答 5

12

你可以写

(\t -> (f1 t, f2 t, f3 t))

免点,这是

liftM (,,) f1 `ap` f2 `ap` f3

带有apfromControl.Monad和from的Monad实例。一种更易读的形式可能是变体(->) aControl.Monad.InstancesControl.Applicative

(,,) <$> f1 <*> f2 <*> f3

然后你可以进一步免点

(\f1 f2 f3 -> (\t -> (f1 t, f2 t, f3 t)))

作为

  \f1 f2 f3 -> (,,) <$> f1 <*> f2 <*> f3
= \f1 f2 -> ((,,) <$> f1 <*> f2 <*>)
= \f1 f2 -> (<*>) ((,,) <$> f1 <*> f2)
= \f1 f2 -> ((<*>) . ((,,) <$> f1 <*>)) f2
= \f1 -> (<*>) . ((,,) <$> f1 <*>)
= \f1 -> (<*>) . (<*>) ((,,) <$> f1)
= \f1 -> (((<*>) .) . (<*>) . (<$>) (,,)) f1
= ((<*>) .) . (<*>) . (<$>) (,,)

但说真的,你不应该。保持可读性,这意味着一点点自由是好的,但不要过度。

于 2012-09-12T19:51:22.090 回答
4

是的。#haskell IRC 频道上的“lambdabot”IRC 机器人实际上有一个功能,可以为您提供给定功能的无点版本。在你的情况下,它说

\x -> (f x, g x, h x)

相当于

ap (liftM2 (,,) f g) h
于 2012-09-12T19:45:21.563 回答
4

尽管 applicative 或 monadic 版本更简单、更短,但可能暴露“含义”(以及您正在使用的 Haskell 类型类别的属性)的一种方法是使用 Control.Arrow

uncurry (uncurry (,,)) . ((f &&& g) &&& h)

pointfull版本虽然优越。

这也暴露了你需要 Hask 的“笛卡尔性”,而不是 Hask 的所有“封闭性”

 arrowized :: Arrow cat => cat a a1 -> cat a b1 -> cat a b -> cat a (a1, b1, b)
 arrowized f g h => arr (uncurry (uncurry (,,))) . ((f &&& g) &&& h)
于 2012-09-12T19:54:52.577 回答
2

你可以这样写你的例子:

\f1 f2 f3 t -> (,,) (f1 t) (f2 t) (f3 t)

(,,) 是一个带有 3 个参数的常用函数,因此使其应用程序无点并没有什么特别之处。但是,它使用它的参数 3 次,所以它会很麻烦,而且可能不值得。

#haskell 的 Lambdabot 说它是(ap .) . liftM2 (,,). 享受 :)

于 2012-09-12T19:52:14.087 回答
2

这里有一些关于其他人的答案的详细说明。

我们在源码里面Control.Applicative找到

instance Applicative ((->) a) where  -- (a ->) is meant here
    pure = const
    (<*>) f g x = f x (g x)

liftA3 f a b c = f <$> a <*> b <*> c

在 GHCi 中,我们得到

Prelude Control.Applicative> :t liftA3 (,,)
liftA3 (,,) :: (Applicative f) => f a -> f b -> f c -> f (a, b, c)

因此,使用(t->)as fliftA3 (,,)就可以了:

liftA3 (,,) ~ (t->a) -> (t->b) -> (t->c) -> (t->(a,b,c))

即,调用liftA3 (,,) f1 f2 f3 t产生一个三元组(f1 t, f2 t, f3 t),给定相同类型输入的三个函数:

Prelude Control.Applicative> liftA3 (,,) (:[]) (quot 12) (`rem`3) 4
([4],3,1)


那么它是怎样工作的?根据 的定义liftA3,然后是<*>

liftA3 (,,) f g h t = ((((,,) <$> f) <*> g) <*> h) t
    = (((,,) <$> f) <*> g) t (h t)
    = (((,,) <$> f) t (g t) (h t)

现在,(<$>) = fmap定义instance Functor ((->) t)fmap = (.)所以我们继续

    = (((,,) . f) t (g t) (h t)
    = (,,) (f t) (g t) (h t)
    = (f t, g t, h t)
于 2012-09-13T15:01:10.417 回答