QualifiedDoが面白い

GHC9.0.1で追加された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.QualifiedDo
はindexed
パッケージの拡張として作成したものだ。

面白いのは、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
これは次のようなごく単純な仕組みで実現されている:
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 ‘ _ <- " "’

これまでも使ってきているが、QualifiedDo
拡張をBlockArguments
拡張と組み合わせることで、さらなる自由度を得られる。
以下の記事はBlockArguments拡張を面白い応用を紹介してくれる。

Monadはモノイドと似た構造なので、モノイドやそれに似た構造のやつは色々突っ込めそう
でもあまりめちゃくちゃをすると読みづらくなってしまいそう。少なくともコンパイラに警告を出されるような用法は控えたほうがいいか。

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