Haskell の「持ち上げ」とは何ですか? 質問する

Haskell の「持ち上げ」とは何ですか? 質問する

「リフティング」が何なのか分かりません。「リフト」が何なのか理解する前に、まずモナドを理解する必要がありますか? (私もモナドについては全く無知です :) それとも、誰か簡単な言葉で説明してもらえますか?

ベストアンサー1

リフティングは数学的な概念というよりも、デザイン パターンです (ただし、ここで誰かが、リフティングがカテゴリであるか何かを示して私に反論するだろうと予想しています)。

通常はパラメータ付きのデータ型があります。

data Foo a = Foo { ...stuff here ...}

Fooの多くの使用が数値型 ( など) を取るIntことに気づきDouble、これらの数値をアンラップし、加算または乗算し、再びラップするコードを記述し続けなければならないとします。アンラップとラップのコードを 1 回記述することで、この処理を省略できます。この関数は、次のようになるため、伝統的に「リフト」と呼ばれます。

liftFoo2 :: (a -> b -> c) -> Foo a -> Foo b -> Foo c

言い換えると、2 つの引数を持つ関数 (演算(+)子など) を受け取り、それを Foos の同等の関数に変換する関数があることになります。

これで、

addFoo = liftFoo2 (+)

編集: 詳細情報

You can of course have liftFoo3, liftFoo4 and so on. However this is often not necessary.

Start with the observation

liftFoo1 :: (a -> b) -> Foo a -> Foo b

But that is exactly the same as fmap. So rather than liftFoo1 you would write

instance Functor Foo where
   fmap f foo = ...

If you really want complete regularity you can then say

liftFoo1 = fmap

If you can make Foo into a functor, perhaps you can make it an applicative functor. In fact, if you can write liftFoo2 then the applicative instance looks like this:

import Control.Applicative

instance Applicative Foo where
   pure x = Foo $ ...   -- Wrap 'x' inside a Foo.
   (<*>) = liftFoo2 ($)

The (<*>) operator for Foo has the type

(<*>) :: Foo (a -> b) -> Foo a -> Foo b

It applies the wrapped function to the wrapped value. So if you can implement liftFoo2 then you can write this in terms of it. Or you can implement it directly and not bother with liftFoo2, because the Control.Applicative module includes

liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c

and likewise there are liftA and liftA3. But you don't actually use them very often because there is another operator

(<$>) = fmap

This lets you write:

result = myFunction <$> arg1 <*> arg2 <*> arg3 <*> arg4

The term myFunction <$> arg1 returns a new function wrapped in Foo:

ghci> :type myFunction
a -> b -> c -> d

ghci> :type myFunction <$> Foo 3
Foo (b -> c -> d)

This in turn can be applied to the next argument using (<*>), and so on. So now instead of having a lift function for every arity, you just have a daisy chain of applicatives, like this:

ghci> :type myFunction <$> Foo 3 <*> Foo 4
Foo (c -> d)

ghci: :type myFunction <$> Foo 3 <*> Foo 4 <*> Foo 5
Foo d

おすすめ記事