星にゃーんのブログ

ほとんど無害。

GHCでFizzBuzz

GHCFizzBuzzを書いた。

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

GHCのコードはHaskellに似ている(これが言いたかっただけ)。