A Function as A Functor and An Applicative

(<$>)の引数が純関数になる時

以下のコードがピンと来なかったので考えてみた(初出:2ch)。

import Control.Applicative
data X = X A B deriving (Show)
newtype A = A Int deriving (Show)
newtype B = B String deriving (Show)
class F x where
toF :: Int -> x
instance F A where
-->> toF 3 :: A
-- A 3
toF = A
instance F B where
-->> toF 3 :: B
--B “3”
toF = B . show
instance F X where
toF = X <$> toF <*> toF -- これが問題
toF 3 :: X      -- 実行すると
(A 3) (B “3”) -- こうなる

(1引数)純関数が (<$>) の引数に来るなんてどういうこと? 3が2回関数適用で使われているのはどういうこと?

なぜか?

以下はFunctorの定義:

class Functor (f :: * -> *) where
fmap :: (a -> B) -> f a -> f b
instance Functor ((->) r) — Defined in ‘GHC.Base’

すなわち r 型を引数に取る1引数関数は(r上の)Fuctorである。Functorとしての関数について


ここで注意事項。 ((->) r) は引数が r の関数を意味する。 決まっているのは返型ではなく引数の型。一方 Functor f => f a とした時、 fに対応するのは ((->) r) 全体である。

class Functor (f :: * -> *) where
...
instance Functor ((->) r) -- Defined in ‘GHC.Base’

なのだから、 f = ((->) r) :: r -> * であり、 f a = ((->) r) a = ((->) r a) :: a となる。 f aa はこの関数の返値を意味する。この関数が何を引数として取るかは隠れてしまっている。(何度勉強してもすぐ混乱する。。。)


次に、以下の型を持つ (<$>) とは、

:t (<$>)
(<$>) :: Functor f => (a -> b) -> f a -> f b
  • aを受け取り bを返す関数
  • 何かを受け取りaを返す関数

を順に受け取り、同じ何かを受け取りb型を返す関数を返す。

次に、 以下の型を持つ(<*>) は、この文脈を踏まえて、

:t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
  • 何かを受け取り、さらに aを受け取ると bを返す関数
  • (型も値も)同じ何かを受け取り aを返す関数

を受け取り、 同じ何かを受け取り b を返す関数を返す。

ということで、例えばこうなる。

(\i x -> take i (repeat x)) <*> (\i -> [i]) 5
=> [[5],[5],[5],[5],[5]]

従って 何かInt , bXと置き換えれば、これは Intからの各フィールドに対応した型変換関数を順番に使って(部分適用を繰り返して)、型 Xを返す関数の適用をしていることになる。

toF 3
=> ((X :: A -> B -> X) <$> (toF :: Int -> A) <*> (toF :: Int -> B)) 3
=> (((X <$> toF) :: Int -> B -> X) <*> (toF :: Int -> B)) 3
=> ((X <$> toF <*> toF) :: Int -> X) 3
=> _ :: X

なるほど。 <*> は関数Functorの場合は引数を分配しているのか。


ということは別の話に影響して来るようだ。

Like what you read? Give Shuji Narazaki a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.