

[箱で考えるFunctor、ApplicativeそしてMonad -
Qiita](https://qiita.com/suin/items/0255f0637921dcdfe83b) に

Maybeの定義が載っていました。

[code]

    class Monad m where    
        (>>=) :: m a -> (a -> m b) -> m b
    
[/code]

そして

[Functors, Applicative Functors and Monoids - Learn You a Haskell for Great
Good!](http://learnyouahaskell.com/functors-applicative-functors-and-monoids)
に

Functorの定義が載っていました。

[code]

    class Functor f where  
        fmap :: (a -> b) -> f a -> f b
    
[/code]

この`m`や`f`が何をさしているのかわかりません。

以前した[質問](https://ja.stackoverflow.com/questions/70022/ambiguous-type-
variable-a0-arising-from-a-use-of-getfromint-prevents-the-con)で 私は
`Changeable` という type class を実装してみました。  
今回の質問に必要なところを再掲します。

[code]

    data Color = Red | Green
    
    class Changeable a where
      change :: a -> a
    
    instance Changeable Color where
      change Red = Green
      change Green = Red
    
[/code]

上記のように `Color型` を作って、`change`関数によって
RedならGreenに入れかえ、GreenならRedに入れ替えるというプログラムになっています。

ここで Monad とまったく同じ形をした MyMonad というのを使って感覚をつかもうとしました。

[code]

    class MyMonad m where
      (>>>) :: m a -> (a -> m b) -> m b
    
[/code]

まず上記のように書いて、次に Color
に適合（これはSwiftでProtocolを実装するときに使う単語です。Haskellではなんというのか知らないので知っていたら教えてほしいです）してみようとしました。

[code]

    instance MyMonad Color where
      >>>
    
[/code]

ここまで書いてみて手がとまってしまいました。

[箱で考えるFunctor、ApplicativeそしてMonad -
Qiita](https://qiita.com/suin/items/0255f0637921dcdfe83b) を見てみると Monad を Maybe
に適合させた書き方は下記になっていました。

[code]

    instance Monad Maybe where
        Nothing >>= func = Nothing
        Just val >>= func  = func val
    
[/code]

`Nothing` と `Just` が `>>=` の左側に書かれています！ ちょっと `instance Changeable`
の応用で書けそうにありませんでした。

[code]

    class Changeable a where
      change :: a -> a
    
[/code]

の場合は `a` は Color に適合した場合 `Color` を表すことになると思うのですが、 `class Functor f`の`f`や`class
MyMonad m`の `m` はどのように解釈したらいいのでしょうか？ そしてこれらを適合させている `instance`
の記法は一体どういう仕組になっているのでしょうか？

もしかしたら `Color型`ではなくて、[こちら](https://ja.stackoverflow.com/questions/70029/error-
non-type-variable-argument-in-the-constraint-num-maynull-a-use-
flexib)で質問したときに使った自前のMaybeぽいもの`MayNull型`のほうが、回答を得やすいかもしれないので、本質問に再掲します。

[code]

    data MayNull a = Have a | Null deriving Show
    
[/code]

必要そうであれば、`Color型`に`MyMonad`を適合するのではなく、`MayNull型`に適合する形で使用していただけると私の理解が深まるかもしれないので助かります。

ちなみに使い方はわかっているつもりです。

[code]

    hoge = Just 1  -- Justにラップされた1をhogeに代入
    
    inc x = x + 1  -- xを受け取り+1して返す関数
    incWrapedJust x = Just(x + 1) -- xを受け取り+1してJustでラップして返す関数
    
    hoge >>= incWrapedJust -- hogeをアンラップしたものを引数として使ってJustで返す
    inc <$> hoge -- incはJustを受け取れないかつJustを返せないけどJustを渡せるしJustで返せる
    
[/code]


CC BY-SA 4.0
2020-09-01T08:46:05.150
70043
2020-09-01T12:43:32.560
2020-09-01T11:22:28.230
9008
9008
question
haskell
MonadのmやFunctorのfが何をさしているのかわからない。そして instance 側の記法もわからない。


これは[ドキュメント](https://hackage.haskell.org/package/base-4.14.0.0/docs/Prelude.html#t:Monad)を眺めるとわかりやすいかもしれません。

`Monad`の`Instances`のところに`Monad m`の形をしたものが並んでいますが、`m`に当たるものはすべて
**型を一つ引数に取る型構築子** になっています。面白いのは(自身は２つ型を取る)`Either`で部分適用を行っています。

>
[code]

>      instance Monad (Either e) where
>         Left  l >>= _ = Left l
>         Right r >>= k = k r
>  
[/code]

そのため`Color`を`MyMonad`のインスタンスにすることはできません。`MayNull`の方は例えば次のように書けるでしょうか。

[code]

    instance MyMonad MayNull where
        -- 実装はMaybeの模倣
        (Have x) >>> f = f x
        Null >>> _ = Null
    
[/code]

ただドキュメントにあるように、標準ライブラリの`Monad`クラスは`m`が`Applicative`クラスのインスタンスであることと、「モナド則」を満たす必要があることに注意してください。特に後者はコンパイラがチェックしてくれないので、プログラマの責任で正しく実装しなければなりません。

* * *

「適合」に相当する用語はちょっとでてこないのですが

[code]

    instance A B where
    
[/code]

みたいに書いた時、「型`B`は型クラス`A`のインスタンスである」という言い方はします。


CC BY-SA 4.0
2020-09-01T10:13:37.907
70046
2020-09-01T10:13:37.907
13199
70043
answer


> Nothing と Just が >>= の左側に書かれています！

についてはまだ回答で言及がなかったので補足すると、Haskellにおいて演算子を定義するときはそのように書くことができます。  
一般に、

[code]

    instance SomeTypeClass SomeType where
      ...
    
[/code]

の`...`の部分に書くことができるものは、関数を定義するときに書けるものと（細かい違いはありますが）概ね同じです。

なので、仮に`>>=`が`Monad`型クラスのメソッドではなく普通の関数だとしたら、

[code]

    module SomeModule where
    
    ...
    
    (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
    Nothing >>= func = Nothing
    Just val >>= func  = func val
    
[/code]

と、モジュールのトップレベルに書いたり、

[code]

    let Nothing >>= func = Nothing
        Just val >>= func = func val
     in
      ...
    
[/code]

と、`let`や`where`を使って、ローカル変数の定義でも上記のように書くことができます。

ちなみに、演算子の定義方法には、もう少し親しみのある（？）、カッコで囲って前置記法にする方法もあります:

[code]

    (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b
    (>>=) Nothing func = Nothing
    (>>=) (Just val) func  = func val
    --    ^ Just val をカッコで囲う必要がある点に注意
    
[/code]

こちらは `Nothing >>= func = ...` などと中置記法で書く方法と全く意味は変わりません。


CC BY-SA 4.0
2020-09-01T11:46:49.427
70049
2020-09-01T12:43:32.560
2020-09-01T12:43:32.560
8007
8007
70043
answer