bonotakeの日記

元・ソフトウェア工学系研究者、今・AI系エンジニア

テンプレートモナド 追補

こないだ載せたテンプレートモナドの記事ですが、

型がイイカゲンな言語のほうが楽ちんに実装できますけど、本来のモナド概念は強い(ものすごく強い)型を背景とした定式化になっています。

こういうところ、あんまり厳密に書いてませんでした。
※ 個人的には、例えば {"greeting", "body", "sign"} をTextのサブセットとして定義したかったのですが。あんまり(自分の直観に従いつつ、面倒くさくない)いい方法が見つからず、ちょっと不満だったり。
一応、そこいらへんを強化して、型を厳しくした修正例を書いておきます。尚、モナドの定義はそのままで対応できます。

data DataA = Greeting | Body | Sign deriving Show
data DataB = Person | GoodOrBad deriving Show

DataAとかDataBとかは、文字列のサブセットだと脳内変換して読んでくれるとうれしいですw

{- テストデータ -}
message :: Template DataA
message = C [N Greeting, T " ", N Body, T " -- ", N Sign]

confun1 :: DataA -> Template DataB
confun2 :: DataB -> Template ()

confun1 Greeting =  C [T "Hello, ", N Person, T "."]
confun1 Body = C [T "It's a ", N GoodOrBad, T " News, ..."]
confun1 Sign = T "Hanako"

confun2 Person = T "Tonkichi"
confun2 GoodOrBad = T "Good"

表示用に、resolveを修正。

{- テンプレートからテキストへ -}
resolve :: Show a => Template a -> Text
resolve (T s) = s
resolve (N n) = "{" ++ (show n) ++ "}"
resolve (C ss) = foldl1 (++) (map resolve ss)

実行例。うまくいく例と、型エラーを吐く例。

*Main> resolve $ message >>= confun1
"Hello, {Person}. It's a {GoodOrBad} News, ... -- Hanako"
*Main> resolve $ message >>= confun2

<interactive>:1:22:
    Couldn't match `DataB' against `DataA'
      Expected type: DataA -> Template b
      Inferred type: DataB -> Template ()
    In the second argument of `(>>=)', namely `confun2'
    In the second argument of `($)', namely `message >>= confun2'
注:bonotakeは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。