gen_nats(Max, Ns) :- true | gen_integers(1, Max, Ns). gen_integers(N, Max, Is) :- N =< Max | Is = [N | Is1], N1 := N + 1, gen_integers(N1, Max, Is1). gen_integers(N, Max, Is) :- N > Max | Is = []. map([], Fs) :- true | Fs = []. map([N|Ns], Fs) :- N mod 15 =:= 0 | Fs = [fizzbuzz|Fs1], map(Ns, Fs1). map([N|Ns], Fs) :- N mod 3 =:= 0, N mod 5 =\= 0 | Fs = [fizz|Fs1], map(Ns, Fs1). map([N|Ns], Fs) :- N mod 3 =\= 0, N mod 5 =:= 0 | Fs = [buzz|Fs1], map(Ns, Fs1). map([N|Ns], Fs) :- N mod 3 =\= 0, N mod 5 =\= 0 | Fs = [N|Fs1], map(Ns, Fs1). print([S|Ss], IOs) :- true | IOs = [write(S), nl | IOs1], print(Ss, IOs1). print([], IOs) :- true | IOs = [].
コードの見た目はPrologに近いが、逐次性が無い、ガード節がある、などの理由でPrologで書いたものとはかなり異なる…はず。
実行はこんな感じ
?- ghc genNats(10, Ns), map(Ns, Fs), print(Fs, Os), outstream(Os). 1 2 fizz 4 buzz fizz 7 8 fizz buzz Ns = [1, 2, 3, 4, 5, 6, 7, 8, 9|...], Fs = [1, 2, fizz, 4, buzz, fizz, 7, 8, fizz|...], Os = [write(1), nl, write(2), nl, write(fizz), nl, write(4), nl, write(...)|...].
GHCつながりでHaskell版も書いてみた。GHC版と似せるためにちょっと変な書き方をしている。
module Main where genNats :: Int -> [Int] genNats m = genIntegers 1 m genIntegers :: Int -> Int -> [Int] genIntegers n m | n <= m = n : genIntegers (n + 1) m | otherwise = [] map' :: [Int] -> [String] map' [] = [] map' (n:ns) | n `mod` 15 == 0 = "fizzbuzz" : map' ns | n `mod` 3 == 0 = "fizz" : map' ns | n `mod` 5 == 0 = "buzz" : map' ns | otherwise = show n : map' ns main :: IO () main = mapM_ putStrLn (map' (genNats 10))
実行するとこんな感じ
1 2 fizz 4 buzz fizz 7 8 fizz buzz