4

ポイントフリー関数はタプルを返すことができますか? たとえば、ポイントフリー スタイル (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

apfromとfromControl.MonadMonadインスタンス。やや読みやすい形式は、バリアントである可能性があります(->) 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

アプリカティブまたはモナド バージョンはよりシンプルで短いですが、おそらく「意味」(および使用している Haskell 型のカテゴリのどのプロパティ) を明らかにする 1 つの方法は、Control.Arrow を使用することです。

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

ただし、ポイントフル バージョンの方が優れています。

これは、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

ここで、他の人の回答について詳しく説明します。

のソースコードの中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を使用するとf、次のliftA3 (,,)ように機能します。

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

つまり、同じ型の入力に対して 3 つの関数が与えられた場合、 を呼び出すとliftA3 (,,) f1 f2 f3 ttriple が生成されます。(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 に答える
2

次のように例を書くことができます:

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

(,,) は 3 つの引数を持つ通常の関数なので、そのアプリケーションを無意味にすることに特別なことは何もありません。ただし、引数を 3 回使用するため、面倒になり、おそらく価値がありません。

#haskell の Lambdabot は、それは(ap .) . liftM2 (,,). 楽しみ :)

于 2012-09-12T19:52:14.087 に答える