문제

Can a pointfree function return a tuple? For instance, can the following be written in pointfree style (where f1, f2, and f3 have been defined):

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

In this case, my f1, f2, and f3 are compositions of quot, mod, *, and some integers.

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

is a more general case, and is equivalent to

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

Named functions are OK, but my examples are anonymous. (Named examples would be as follows)

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

EDIT: I'm just curious for fun, I'm not going to do this.

도움이 되었습니까?

해결책

You can write

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

pointfree, it's

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

with ap from Control.Monad and the Monad instance of (->) a from Control.Monad.Instances. A somewhat more readable form may be the Control.Applicative variant

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

You can then further point-free

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

As

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

but seriously, you shouldn't. Keep it readable, that means a bit of pointfreeing is good, but don't overdo it.

다른 팁

Yes. The "lambdabot" IRC bot on the #haskell IRC channel actually has a feature which gives you the point-free version of a given function. In your case, it says that

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

is equivalent to

ap (liftM2 (,,) f g) h

Although the applicative or monadic version is simpler and shorter, one way that perhaps exposes the "meaning" (and what property of the category of Haskell types you are using) is using Control.Arrow

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

The pointfull version is superior though.

This also exposes that you need the "Cartesianess" of Hask, but not all the "Closedness" of 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)

You can write your example like this:

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

(,,) is a usual function with 3 arguments, so there's nothing special in making its application pointfree. However, it uses its argument 3 times so it's going to be cumbersome and it's probably not worth it.

Lambdabot at #haskell says it's (ap .) . liftM2 (,,). Enjoy :)

Here's some elaboration on the other's answers here.

Inside the source code for Control.Applicative we find

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

In GHCi, we get

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

So, with (t->) as f, liftA3 (,,) just works:

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

I.e., calling liftA3 (,,) f1 f2 f3 t produces a triple (f1 t, f2 t, f3 t), given three functions on same-type input:

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


So, how does it work? By the definiton of liftA3, and then of <*>,

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

Now, (<$>) = fmap and instance Functor ((->) t) defines fmap = (.), so we continue

    = (((,,) . f) t (g t) (h t)
    = (,,) (f t) (g t) (h t)
    = (f t, g t, h t)
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top