Open6

QualifiedDoが面白い

りんすりんす

公式ドキュメントでは以下の要素が触れられている。

(e.g. indexed monads, graded monads or relative monads)

例えばIndexed monadsの一種であるIxStateを使うと、次のように途中で状態の型を変えられるStateモナドっぽいやつIxStateを作ることができる。Index monads用のdo文を使えば、本当のモナドのように扱える。

Indexed monads用のdo文を使うときには、Indexed.doのようにしてdoキーワードをモジュール名で修飾する。

{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE QualifiedDo    #-}
import qualified Control.Monad.Indexed.QualifiedDo as Indexed
import           Control.Monad.IxState

main :: IO ()
main = do
  print $ runIxState
    Indexed.do
      imodify (* 2)
      imodify \n ->
        "Hello " <> show n
    do 10 :: Int
("Hello 20",())

このControl.Monad.Indexed.QualifiedDoindexedパッケージの拡張として作成したものだ。
https://github.com/reinerp/indexed/pull/11/files

りんすりんす

面白いのは、Qualified doはもはやMonadには縛られないので、様々な演算を行えることだ。

以下は、Writerモナドを使う代わりにQualified Doを使う例だ。

{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE QualifiedDo    #-}
import qualified Data.Monoid.QualifiedDo as Monoid

main :: IO ()
main = do
    putStrLn Monoid.do
        "Hello"
        " "
        "World"
Hello World

これは次のようなごく単純な仕組みで実現されている:

Data/Monoid/QualifiedDo.hs
module Monoid.QualifiedDo ((>>)) where

import           Data.Monoid
import qualified Prelude

(>>) :: Monoid m => m -> m -> m
m >> n = m <> n

ただこの用法は通常のdo文の意味論から離れすぎているからか、次のような警告が出てしまう。もちろん、Data.Monoid.QualifiedDoには>>=を用意していないため、提案される書き換えを実施するとコンパイルエラーとなる。

A do-notation statement discarded a result of type ‘ Char’
Suggested fix: Suppress this warning by saying ‘ _ <- " "’

りんすりんす

Monadはモノイドと似た構造なので、モノイドやそれに似た構造のやつは色々突っ込めそう

でもあまりめちゃくちゃをすると読みづらくなってしまいそう。少なくともコンパイラに警告を出されるような用法は控えたほうがいいか。

りんすりんす

constrained monads、linear monadsなんてのもモナドのバリアントであるらしい
そのうち見よう