関数のWrapperと持ち上げ(lifting)

「関数の持ち上げ(lifting)」という概念を多用する言語はあまりない気がしたので書きました。
先に書いておくと、僕はポイントフリーはうまく読めないのであまり使いません。


# 関数のwrapperとしての高階関数

関数が第一級である言語は、高階関数を用いることにより、関数に対して同じ型の関数を返すことが出来ます。

```hs
addLogging :: (Int -> IO Int) -> (Int -> IO Int)
addLogging act = \n -> do
  r <- act n
  log "heyhey"
  return r
```

引数`act`を受け取り、そのアクションにロギングを追加しつつ、同じ型のアクションを返しています。高階関数を用いて、関数の適切なwrapperを作ることが出来るということです。


# 高階関数による引数の型変換

以下の3関数が与えられているとします。

```hs
f :: Int -> Int
show :: Int -> String
read :: String -> Int
```

ここで`show`, `read`はそれぞれ`Int`, `String`間の変換関数であり、パーズ失敗等は考慮しないものとします。つまり、`show`と`read`はお互い逆関数とします。
以上の3関数のみを用いて、以下の関数を作ることを考えます。

```hs
si_f :: String -> Int
is_f :: Int -> String
ss_f :: String -> String
```

引数が`String`になっているなら、`read`を用いてから`f`へ渡し、
返り値が`String`になっているならば、`show`を用いて`f`からの返り値を変換すればいいでしょう。例えば以下です：

```hs
si_f :: String -> Int
si_f s = f (read s)

is_f :: Int -> String
is_f i = show (f i)

ss_f :: String -> String
ss_f s = show $ f (read s)
```

よって、`Int -> Int`の関数を`String -> String`の関数に変換する関数は以下の様にかけます：

```hs
ii2ss :: (Int -> Int) -> (String -> String)
ii2ss f = \s -> show $ f (read s)
```

まあ`ss_f`の`f`を引数で渡すようにしただけなので問題ないでしょう。他も同様にかけますが省略します。


# 複雑な関数の変換

同様に以下の関数`g`, `show`, `read`を用いて、引数の型の変換を考えます。

```hs
g :: (Int -> Int) -> Int
g = undefined
```

例えば以下です：

```hs
sii_g' :: (String -> Int) -> Int
sii_g' = \ si -> g (\ i -> si $ show i)

isi_g' :: (Int -> String) -> Int
isi_g' = \ is -> g (\ i -> read $ is i)

iis_g' :: (Int -> Int) -> String
iis_g' ii = show $ g ii

sss_g' :: (String -> String) -> String
sss_g' = \ ss -> show $ g (\ i -> read $ ss $ show i)
```

まあこれでもいいのですが、後のために規則性をつけて記述してみます。

```hs
sii_g :: (String -> Int) -> Int
sii_g si =
    let
        trans :: (String -> Int) -> (Int -> Int)
        trans si i = si (trans' i)

        trans' :: Int -> String
        trans' = show
    in
        g (trans si)

isi_g :: (Int -> String) -> Int
isi_g is =
    let
        trans :: (Int -> String) -> (Int -> Int)
        trans is i = read $ is i
    in
        g (trans is)

iis_g :: (Int -> Int) -> String
iis_g ii = show $ g ii

sss_g :: (String -> String) -> String
sss_g ss =
    let
        trans :: (String -> String) -> (Int -> Int)
        trans ss i = read $ ss (trans' i)

        trans' :: Int -> String
        trans' = show
    in
        show $ g (trans ss)

```

`g`を活用するためには、`g`へ渡す関数の型を`Int -> Int`にしてから渡す必要があります。そのために、`trans`関数を挟んで型を変換しています。

これで`((Int -> Int) -> Int) -> ((String -> String) -> String)`といった関数も作れるようになりました。構築には`g`, `show`, `read`しか使っていないため、関数の意味を変えるようなことはしていません。


# さらに複雑な関数の変換

以下の関数を考慮します。

```hs
h :: ((Int -> Int) -> Int) -> Int
h = undefined
```

全て記述すると長くなるので二つだけにしておきます。

```hs
siii_h :: ((String -> Int) -> Int) -> Int
siii_h sii =
    let
        trans :: ((String -> Int) -> Int) -> ((Int -> Int) -> Int)
        trans sii ii = sii $ trans' ii

        trans' :: (Int -> Int) -> (String -> Int)
        trans' ii s = ii $ trans'' s

        trans'' :: String -> Int
        trans'' = read
    in
        h $ trans sii

ssss_h :: ((String -> String) -> String) -> String
ssss_h sss =
    let
        trans :: ((String -> String) -> String) -> ((Int -> Int) -> Int)
        trans sss ii = read $ sss (trans' ii)

        trans' :: (Int -> Int) -> (String -> String)
        trans' ii s = show $ ii (trans'' s)

        trans'' :: String -> Int
        trans'' = read
    in
        show $ h (trans sss)
```

規則性が見えるでしょうか。
`h`には`(Int -> Int) -> Int`の関数しか渡せないので、一旦`trans :: ((String -> Int) -> Int) -> ((Int -> Int) -> Int)`を定義します。
<b>`trans`はよく見ると二引数関数です。</b>`(->)`が右結合であることを考慮すると、

```hs
trans
  :: ((String -> Int) -> Int)
  -> ((Int -> Int) -> Int)
trans
  :: ((String -> Int) -> Int)
  -> (Int -> Int)
  -> Int
```

は同じ型の関数であることがわかります。

```hs
trans :: ((String -> Int) -> Int) -> (Int -> Int) -> Int
trans sii ii = undefined -- 2引数置いた
```

この二引数を使って`Int`を作るには、`Int -> Int`の関数を`String -> Int`に変換して`sii`へ渡せば良さそうです。その変換関数を`trans'`とします。

```hs
trans :: ((String -> Int) -> Int) -> (Int -> Int) -> Int
trans sii ii = sii (trans' ii) -- iiの変換をtrans' に任せつつsiiに渡した
```

`trans'`の中身は先ほど同じようなことをしたので、直接書き下せます。

以上のようにして、関数全体が定義できました。

# もっと複雑な関数の変換

以下の関数を考慮します。

```hs
k :: (((Int -> Int) -> Int) -> Int) -> Int
k = undefined
```

初めの引数だけ`String`に変換した関数を書き下します：

```hs
siiii_k :: ((((String -> Int) -> Int) -> Int) -> Int)
siiii_k siii =
    let
        trans :: (((String -> Int) -> Int) -> Int) -> (((Int -> Int) -> Int) -> Int)
        trans siii iii = siii $ trans' iii

        trans' :: ((Int -> Int) -> Int) -> ((String -> Int) -> Int)
        trans' iii si = iii $ trans'' si

        trans'' :: (String -> Int) -> (Int -> Int)
        trans'' si i = si $ trans''' i

        trans''' :: Int -> String
        trans''' = show
    in
        k $ trans siii
```

もっと不規則な関数を選んでみましょう。

```hs
l :: ((Int -> ((Int -> Int) -> Int)) -> Int) -> Int
l = undefined
```

全て`String`にしてみました：

```hs
ssssss_l :: ((String -> ((String -> String) -> String)) -> String) -> String
ssssss_l sssss =
    let
        trans
            :: ((String -> ((String -> String) -> String)) -> String)
            -> ((Int -> ((Int -> Int) -> Int)) -> Int)
        trans sssss iiii = read $ sssss $ trans' iiii

        trans'
            :: (Int -> ((Int -> Int) -> Int))
            -> (String -> ((String -> String) -> String))
        trans' iiii s ss = show $ iiii (trans'' s) (trans''' ss)

        trans'' :: String -> Int
        trans'' = read

        trans''' :: (String -> String) -> (Int -> Int)
        trans''' ss i = read $ ss (trans'''' i)

        trans'''' :: Int -> String
        trans'''' = show
    in
        show $ l $ trans sssss
```

# 一般化

変換関数`show`, `read`を一般化して、任意の`convert`とその逆関数`inverse`の対で同様の論が行えます。どんな複雑な高階関数の引数の変換も記述できるようになります。その証明は恐らく帰納法で出来るでしょう。


# さらに一般化

僕らは別に、関数の引数の型を全て`String`にしたいわけではありません。
https://hackage.haskell.org/package/acme-stringly-typed-1.0.0.0/docs/Acme-StringlyTyped.html

モナドの持ち上げとその実行について考えてみます。

```hs
run :: MyMonad a -> IO a
lift :: IO a -> MyMonad a
```

この`run`と`lift`は逆関数ぽいですよね。
ならばこの二つの関数を用いて、<b>任意のIOベースの関数をMyMonadへ持ち上げることができる</b>はずです。

例えば`catch`関数です。

```hs
catch   :: Exception e
        => IO a         -- ^ The computation to run
        -> (e -> IO a)  -- ^ Handler to invoke if an exception is raised
        -> IO a
```

これを以下のように<b>持ち上げ(lift)</b>られたら嬉しいですよね：

```hs
catch'  :: Exception e
        => MyMonad a
        -> (e -> MyMonad a)
        -> MyMonad a
```

実装は略します:)


# 一般化の先に

先の`MyMonad`への持ち上げはもっと一般化出来そうですよね。

`monad-control`というライブラリが存在します。
https://hackage.haskell.org/package/monad-control
このライブラリは先の`catch`やら`fork`やら、primitiveでしか存在しないIO操作を、IOを底とした好きなモナドへ持ち上げるためのライブラリです。大雑把に言って。モナド変換子ベースのライブラリですね。
ここまで一般化してくると笑えて来ませんか。僕は笑いました。


# まとめ

* 任意の高階関数は、<b>機械的に</b>引数の型の変換が可能
* 任意のIOアクションは、<b>好きなモナド(IOベース)</b>へ持ち上げることが可能
* 機械的に持ち上げられるなら抽象化できるよね、ということでliftingのためのライブラリが既にある