« 2011年3月 | トップページ | 2012年1月 »

2011年12月

2011年12月15日 (木)

Haskell の配列

 こちらのブログで Haskell の二次元配列の話題が出ていました。
 コードの例が示してあり、「やはりCなどに比べると配列の準備が面倒ですね」と書いてあります。

 私は Haskell の配列に詳しいわけではないのですが、「listArray 関数」を使えば簡単に配列が作れるはずです。
 The Haskell 98 Reportには

配列は関数 listArray を使って境界対とインデックス順に ならべた値のリストから構築することもできる。
と書いてあります。

 

Prelude> :m +Data.Array Prelude Data.Array> listArray (0, 3) [0 .. 3] array (0,3) [(0,0),(1,1),(2,2),(3,3)] Prelude Data.Array> listArray ((0, 0), (1, 1)) [1 .. 4] array ((0,0),(1,1)) [((0,0),1),((0,1),2),((1,0),3),((1,1),4)]
 このように listArray 関数を使えば多次元配列も簡単に作れます。

 「listArray 関数」を使って作った配列には、(!) でインデックスを指定することでアクセスできます(多次元配列にも一発でアクセスできます)。

Prelude Data.Array> let a = listArray ((0, 0), (1, 1)) [1 .. 4] Prelude Data.Array> a array ((0,0),(1,1)) [((0,0),1),((0,1),2),((1,0),3),((1,1),4)] Prelude Data.Array> a ! (0,1) 2

 

 ということで、こちらのブログのコードと同様なコードを「listArray 関数」を使って書いてみました。
 "(!)" で直接アクセスできるので、「seeValue 関数」は定義しませんでした(「makeArray 関数」も定義しなくてよさそうでしたが、これは一応残しました)。

import Data.Array makeArray :: (Int, Int) -> [a] -> Array (Int, Int) a makeArray (x, y) xs = listArray ((1, 1), (x, y)) xs makeRange :: String -> (Int, Int) makeRange cs = (x, y) where [x, y] = map read $ take 2 $ words cs toIntList :: String -> [Int] toIntList cs = map read $ words cs main :: IO () main = do xy <- getLine xs <- getContents let arr = makeArray (makeRange xy) (toIntList xs) print arr print $ arr ! (2, 3)
$ ./array 4 4 1 2 3 4 5 6 7 8 1 2 4 8 7 7 7 7 array ((1,1),(4,4)) [((1,1),1),((1,2),2),((1,3),3),((1,4),4),((2,1),5),((2,2),6),((2,3),7),((2,4),8),((3,1),1),((3,2),2),((3,3),4),((3,4),8),((4,1),7),((4,2),7),((4,3),7),((4,4),7)] 7

2011年12月 1日 (木)

またまた「FizzBuzz」

 かなり久しぶりのブログ更新です。
 最近、また「FizzBuzz問題」が気になりまして……。

 

 一般的な「FizzBuzz問題」といえばこちらのルールですよね。
 Haskell だとこんな感じでしょうか?

fizzbuzz :: [String] fizzbuzz = map f [1 .. ] where f x | rem x 15 == 0 = "FizzBuzz" | rem x 3 == 0 = "Fizz" | rem x 5 == 0 = "Buzz" | otherwise = show x main :: IO () main = putStr $ unlines $ take 100 fizzbuzz

 

 そういえば、「剰余関数を使わない」という制限を加えたものもありましたね。ネット上では次のようなコードが有名(?)だったと思います。

fizzbuzz :: [String] fizzbuzz = zipWith f [1 .. ] $ zipWith (++) fizz buzz where f x "" = show x f _ y = y fizz = cycle ["", "", "Fizz"] buzz = cycle ["", "", "", "", "Buzz"] main :: IO () main = putStr $ unlines $ take 100 fizzbuzz

 

 この方法とは別に、リストの要素に n 個置きに関数を適用する step 関数を Haskell で定義すると、「剰余関数を使わない」で FizzBuzz ができます。

-- リストの先頭から n 個目ごとに f を適用 -- ex : step 3 (\x -> 0) [1 .. 10] => [0,2,3,0,5,6,0,8,9,0] step :: Int -> (a -> a) -> [a] -> [a] step _ _ [] = [] step n f xs = f a : as ++ step n f bs where (a : as, bs) = splitAt n xs fizzbuzz :: [String] fizzbuzz = tail $ foldl conv ss factors where ss = map show [0 ..] factors = [(3, "Fizz"), (5, "Buzz"), (15, "FizzBuzz")] conv ss (a, b) = step a (\ x -> b) ss main :: IO () main = putStrLn $ unlines $ take 100 fizzbuzz

 初めのうちは、ss = map show [0 .. 100] としていたのですが、試しに無限数列にしてみたら、ちゃんと動きました。
 なぜちゃんと動くかが自分でも分っていないのですが、遅延評価ってすごいなぁと思います。

 

 さて、ここからが本題なのですが、「3 と 5 意外の数で FizzBuzz してもいいじゃないか」ということで、任意の数の倍数を任意の文字列で置き換える「拡張版 FizzBuzz」を考えてみました。

{- 任意の数と文字列を指定できる FizzBuzz -} import System.Environment (getArgs) -- ex : fizzbuzz [(2, "Fizz"), (3, "Buzz")] -- -> ["1","Fizz","Buzz","Fizz","5","FizzBuzz","7","Fizz" ..] fizzbuzz :: [(Int, String)] -> [String] fizzbuzz xs = map f [1 ..] where f n = if null str then show n else str where str = foldr g [] xs g (x, cs) tmp = if rem n x == 0 then cs ++ tmp else tmp -- ex : fizzbuzz 100 3 fizz 5 buzz main :: IO () main = do args <- getArgs let n = read (head args) xs = format (tail args) in mapM_ putStrLn $ take n $ fizzbuzz xs where format [] = [] format (n : x : xs) = (read n, x) : format xs

 実行結果は次のようになります。

$ runghc fizzbuzz8.hs 50 2 Fizz 3 Buzz 5 Bar 1 Fizz Buzz Fizz Bar FizzBuzz 7 Fizz Buzz FizzBar 11 FizzBuzz 13 Fizz BuzzBar Fizz 17 FizzBuzz 19 FizzBar Buzz Fizz 23 FizzBuzz Bar Fizz Buzz Fizz 29 FizzBuzzBar 31 Fizz Buzz Fizz Bar FizzBuzz 37 Fizz Buzz FizzBar 41 FizzBuzz 43 Fizz BuzzBar Fizz 47 FizzBuzz 49 FizzBar

« 2011年3月 | トップページ | 2012年1月 »

2016年7月
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            
フォト

最近のトラックバック

無料ブログはココログ