Scrap Your Boilerplate ことはじめ2

昨日のやつのモナド版を作ってみます。

recMapM :: forall a b m. (Data a, Data b, Monad m) => (b -> m b) -> a -> m a
recMapM f x = do
  let recurse = gmapM (recMapM f) x
  case cast x of
    Nothing -> recurse
    Just bx -> do
      z <- f bx
      case cast z of
        Nothing -> recurse
        Just az -> return az

途中Maybe (m (Maybe b))という型になるため、Maybeを手で扱う必要が出てくる必要があっていやーんな感じです。何とかならないものでしょうか。二つのMaybeの文脈は結合したいし、かといってmがMonadMaybeであることを要求したくはないわけで。

ともかくこれがあればモナド無双できます。倍精度実数の部分にちょっとだけ乱数を足すとか。

ghci> recMapM (\x -> getRandomR (x,(1.01::Double)*x)) a1 >>= print
Abc (Bca (Cab (A "Happy") (B 4.215734581306111)) (Abc (B 5.627533165698871) (C 512))) 
  (Cab (Abc (B 8.482016322000884) (C 208)) (Bca (C 2012) (A "New Year!")))

文字列パートを強調する方法をすべて列挙するとか。

ghci> mapM_ print $ recMapM (\str -> [str, "Very " ++ str, "Extremely " ++ str]) a1 
Abc (Bca (Cab (A "Happy") (B 4.2)) (Abc (B 5.6) (C 512))) (Cab (Abc (B 8.4) (C 208)) (Bca (C 2012) (A "New Year!")))
Abc (Bca (Cab (A "Happy") (B 4.2)) (Abc (B 5.6) (C 512))) (Cab (Abc (B 8.4) (C 208)) (Bca (C 2012) (A "Very New Year!")))
Abc (Bca (Cab (A "Happy") (B 4.2)) (Abc (B 5.6) (C 512))) (Cab (Abc (B 8.4) (C 208)) (Bca (C 2012) (A "Extremely New Year!")))
Abc (Bca (Cab (A "Very Happy") (B 4.2)) (Abc (B 5.6) (C 512))) (Cab (Abc (B 8.4) (C 208)) (Bca (C 2012) (A "New Year!")))
Abc (Bca (Cab (A "Very Happy") (B 4.2)) (Abc (B 5.6) (C 512))) (Cab (Abc (B 8.4) (C 208)) (Bca (C 2012) (A "Very New Year!")))
Abc (Bca (Cab (A "Very Happy") (B 4.2)) (Abc (B 5.6) (C 512))) (Cab (Abc (B 8.4) (C 208)) (Bca (C 2012) (A "Extremely New Year!")))
Abc (Bca (Cab (A "Extremely Happy") (B 4.2)) (Abc (B 5.6) (C 512))) (Cab (Abc (B 8.4) (C 208)) (Bca (C 2012) (A "New Year!")))
Abc (Bca (Cab (A "Extremely Happy") (B 4.2)) (Abc (B 5.6) (C 512))) (Cab (Abc (B 8.4) (C 208)) (Bca (C 2012) (A "Very New Year!")))
Abc (Bca (Cab (A "Extremely Happy") (B 4.2)) (Abc (B 5.6) (C 512))) (Cab (Abc (B 8.4) (C 208)) (Bca (C 2012) (A "Extremely New Year!")))