前回までのプログラムはこちら
とりあえず、
をモナドでつなげてみることに。
つなげられるのがモナドのいいところ(なのか?)
import List import Monad main = putStr $ unlines $ map format $ perm [0,1,2,3,5,6,7,8,9] >>= filter1 >>= filter2 perm :: [Int] -> [[Int]] perm [] = [[]] perm xs = concat [map (x:) $ perm (delete x xs) | x <- xs] test :: [Int] -> Bool test [a,b,c,d,e,f,g,h,i] = if (400 + a*10 + b) * (c*10 + d) == (e*10000 + f*1000 + g*100 + h*10 + i) then True else False format :: [Int] -> String format [a,b,c,d,e,f,g,h,i] = listToString [4,a,b] ++ " x " ++ listToString[c,d] ++ " = " ++ listToString [e,f,g,h,i] listToString :: (Show a) => [a] -> String listToString l = concatMap show l -- 数式を満たせるかどうか filter1 :: [Int] -> [[Int]] filter1 xs = if test xs == True then [xs] else mzero -- 計算結果の先頭がゼロ以外 filter2 :: [Int] -> [[Int]] filter2 xs = if (head $ snd $ splitAt 4 xs) == 0 then mzero else [xs]
結果はこう。
402 x 39 = 15678 495 x 36 = 17820
なんだか若干重かったですが、一応できました。
計算のところは、
perm [0,1,2,3,5,6,7,8,9] >>= filter1 >>= filter2
ですっきり!?
filter1、filter2関数で、条件に当てはまらないときmzeroってのを返却するようにしてますが、これを空リストの空リストにすると、空リストが大量に結果に含まれてしまい、大変なことになります。
concatMapするときに、リストをconcatMapするのと、リストのリストをconcatMapするのとの違いだと思うんですが、まあよく分かりません(汗
ちなみに、昨日やった文字列のリストを扱ったサンプルについて、空リストをmzeroに置き換えてみると、同じように動きます。
import Monad main = print $ ["aaa", "bbb", "ccc", "bbc"] >>= startsWithB >>= endsWithC startsWithB :: String -> [String] startsWithB xs = if (head xs) == 'b' then [xs] else mzero endsWithC :: String -> [String] endsWithC xs = if (head $ reverse xs) == 'c' then [xs] else mzero
結果はこう。
["bbc"]
いい感じです。