6
5

More than 5 years have passed since last update.

関数はモナドである

Posted at

今更だけれど、ネット巡回していて気付いた。

Functor, Applicative で説明したように -> は中置演算子で、関数の型は (->) r a と書くこともできます。(->) r を型コンストラクタと考えると、関数のモナドの定義を導くことができます。

instance Monad ((->) r) where
    return = const
    f >>= k = \ r -> k (f r) r

というわけで、PHPのカリー化関数クラスはこうなった。(一部省略)

<?php
class Func extends Curry implements Monad
{
    use MonadTrait;

    public function __construct(callable $f)
    {
        $this->value = static::curry($f);
    }

    // Functor
    public function fmap(callable $f)
    {
        return $this->compose($f);
    }

    // Applicative
    public static function pure($a)
    {
        return new static($a);
    }

    // Applicative
    public function ap(Applicative $f)
    {
        assert($f instanceof static);

        return $this->fmap($f);
    }

    // Monad
    public static function ret($value)
    {
        // const
        return new static(function($_) use ($value){
            return $value;
        });
    }

    // Monad
    public static function fail($msg = null)
    {
        throw new \RuntimeException($msg);
    }

    // Monad
    public function bind(callable $f)
    {
        return new static(function($a) use ($f){
            if (!($f instanceof self))
                $f = new self($f);
            return $f($this($a), $a);
        });
    }
}

データベースとかファイルとか何らかのリソースを操作するクラスがあるとする。
それに対して、何らかの処理をする関数がいくつかある。

function getUser($userId, $db)
{
  return $db->getUser($userId);
}

function getFriends($user, $db)
{
  return $db->getAllFriends($user->myTeams);
}

function getFavorites($friends, $db)
{
  return $db->getFavorites($friends);
}

この場合、各関数のカリー化されたものがあるとすると

$combine = $getUser($userId)
         ->bind($getFriends)
         ->bind($getFavorites);
$friendFavs = $combine($db);

関数をbindした後にdbを渡すと、全ての関数に連動してdbが行き渡る。
引数の順番が重要。

f >>= k = \ r -> k (f r) r

f と k を bind で繋げると、最後に適用する r が f と k にも適用されるようになっている。

6
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5