Posted on June 26, 2018 authored by Shinya Yamaguchi

Last Updated June 26, 2018

はじめに

Continuation (継続) について全く勉強したことが無いので Control.Monad.Cont で定義されている ContT とかいつ使うんだろうなーと思っていましたが、ついに利用機会がありました！！！

僕が考えたんじゃなくて fumieval さんに相談して、教えてもらったんですけどね。

問題のコード

Yesod の Handler ではパラメータの取得するために lookupGetParam や lookupPostParam を利用すると思います。

実際にはこんな感じでパラメータを取得していくつか処理を行います。

deleteTestR :: Handler Html = do deleteTestR <- lookupPostParam "key" mParamlookupPostParam case mParam of mParam Nothing -> returnJson $ String "パラメータが不正です。" returnJson Just param -> param case textToSqlKey param of textToSqlKey param Nothing -> returnJson $ String "キーが見つかりませんでした。" returnJson Just key -> do key <- runDB $ get key mRecordrunDBget key case mRecord of mRecord Nothing -> returnJson $ String "削除対象のデータが見つかりませんでした。" returnJson Just _ -> returnJson $ String "success" returnJson

このコード、どう考えても嫌な感じですよね・・・。ネストやばいし。

do で書くと Maybe 型なので値を返せないし、ベースに Handler モナドがあるので Either で置き換えるのも良くわかんないな・・・。と思って、結構放置してました。

ContT を使ってリファクタリング！

先程のプログラムを ContT で置き換えるとこうなります。

deleteTestR :: Handler Html = do deleteTestR <- lookupPostParam "key" mParamlookupPostParam $ do evalContT <- mParam !? "パラメータが不正です。" parammParam <- textToSqlKey param !? "キーが見つかりませんでした。" keytextToSqlKey param <- lift $ runDB $ get key mRecordliftrunDBget key <- mRecord !? "削除対象のデータが見つかりませんでした。" deletedBrandmRecord $ returnJson $ String "success" liftreturnJson where Nothing !? e = ContT $ const $ returnJson $ String e returnJson Just a !? _ = ContT ( $ a) a)

感動しましたね。継続すごいな！って。

まとめ

継続勉強しよ。