7

私はいくつかのコードを見直していて、次の宝石に出くわしました。これは、pointfree出力のコピーアンドペーストであると思います:

(私は、以下が通常よりも適切だと思いましたfoo/barこの特定の質問について:P)

import Control.Monad (liftM2)

data Battleship = Battleship { x :: Int
                             , y :: Int
                             } deriving Show

placeBattleship :: Int -> Int -> Battleship
placeBattleship x' y' = Battleship { x = x', y = y' }

coordinates :: Battleship -> (Int, Int)
coordinates = liftM2 (,) x y



(i)coordinates b = (x b, y b)

から

(ii)に単純化するために必要な手順を説明してくれる人は親切でしょうかcoordinates = liftM2 (,) x y? 特に、背景にモナドが潜んでいることにさえ気づいていなかったので

、 の使用については少し混乱しています。liftM2

(i) は次のように表すこともできますがcoordinates s = (,) (x s) (y s)、どこでどのように進めればよいかわかりません。


PS以下は、それがからだと思われる理由ですpointfree(出力はからGHCIであり、:plにエイリアスされていpointfreeます):

λ: :pl coordinates s = (x s, y s)
coordinates = liftM2 (,) x y
4

3 に答える 3

10

これは、「リーダーモナド」とも呼ばれるのMonadインスタンスを利用します。これは、特定の型から まで(->) rの関数のモナドです。(そもそもなぜそれが存在するのかについての動機については、こちらをご覧ください。)a

さまざまな関数でどのように機能するかを確認するにはm(r ->inに置き換えm aます。たとえば、 を実行するliftMと、次のようになります。

liftM :: (a -> b) -> (m a -> m b)
liftM :: (a -> b) -> ((r -> a) -> (r -> b))
      :: (a -> b) -> (r -> a) -> (r -> b) -- simplify parentheses

...これは単なる関数合成です。きちんとした。

に対しても同じことができますliftM2:

liftM2 :: (a -> b -> c) -> m a -> m b -> m c
liftM2 :: (a -> b -> c) -> (r -> a) -> (r -> b) -> (r -> c)

つまり、引数が 1 つの関数を 2 つ、引数が2つの関数で構成する方法がわかります。これは、通常の関数構成を複数の引数に一般化する方法です。アイデアは、引数が 1 つの関数の両方にそれを渡すことにより、引数を 1 つ取る関数を作成し、r引数を 2 つの関数に渡す 2 つの引数を取得するというものです。f :: (r -> a)したがって、g :: (r -> b)とがあれば、次のようになりh :: (a -> b -> c)ます。

\ r -> h (f r) (h r)

さて、これはあなたのコードにどのように適用されますか? (,)は引数が 2 つの関数であり、xyは型の引数が 1 つの関数ですBattleship -> Int(フィールド アクセサーがそのように機能するため)。これを考慮して:

liftM2 (,) x y = \ r -> (,) (x r) (y r)
               = \ r -> (x r, y r)

このように複数の関数を合成するという考え方を理解すると、このようなポイントフリー コードはかなり読みやすくなります。ポイントフリー ツールを使用する必要はありません。この場合、ポイントフリーでない方が良いと思いますが、ポイントフリー自体は悪くないです。

于 2014-11-19T23:42:54.203 に答える
1

簡単に書き直せます

data Battleship = Battleship { x :: Int
                             , y :: Int
                             } deriving Show

placeBattleship :: Int -> Int -> Battleship
placeBattleship x y = Battleship x y

coordinates :: Battleship -> (Int, Int)
coordinates  (Battleship x y) = (x, y)

ポイントフリースタイルではありませんが、かなりシンプルです

于 2014-11-20T08:48:54.050 に答える