Skip to content

Instantly share code, notes, and snippets.

@shtaag
Created July 22, 2012 17:58
Show Gist options
  • Save shtaag/3160513 to your computer and use it in GitHub Desktop.
Save shtaag/3160513 to your computer and use it in GitHub Desktop.
Start_Haskell_2 exercise in chap.5
問題13
リストのリストを取って、要素のリストを連結する関数concat :: [[a]] -> [a]は 第6章の演習問題で定義した。これをfoldrを使って実装した関数concatRを 定義せよ。さらに、foldlを使って実装した関数concatLを定義せよ。
以下の実行例で自分の定義が正しいことを確認せよ。
> concatR [[1,2],[3],[],[4,5]]
[1,2,3,4,5]
> concatL [[1,2],[3],[],[4,5]]
[1,2,3,4,5]
> concatR []
[]
> concatL []
[]
注)実行には以下のモジュールをcabal installする必要があるかも
cabal install test-framework
cabal install test-framework-quickcheck
cabal install test-framework-quickcheck2
cabal install test-framework-hunit
cabal install test-framework-th
cabal install criterion
\begin{code}
{-# LANGUAGE TemplateHaskell #-}
import Data.List
import Test.QuickCheck
import Test.HUnit
import Test.Framework.TH
import Test.Framework.Providers.HUnit
import Test.Framework.Providers.QuickCheck2
import Criterion.Main
-- 俺なりの実装
concatR :: [[a]] -> [a]
concatR = foldr (\x acc -> x ++ acc) []
concatL :: [[a]] -> [a]
concatL = foldl (++) []
concatL' :: [[a]] -> [a]
concatL' = foldl' (++) []
-- test-framework実行のためのmain
main :: IO ()
main = $(defaultMainGenerator)
-- main = runTests concatTests (TemplateHaskellを使わない場合)
-- criterion実行のためのmain
mainBench = do
let input = [[1..100000],[1..100000],[1..100000]]
defaultMain
[bench "concatR" $ nf concatR (input :: [[Int]])
, bench "concatL" $ nf concatL (input :: [[Int]])
, bench "concatL'" $ nf concatL' (input :: [[Int]])
]
-- prop_で、関数が満たして欲しい性質を書く。TemplateHaskellがquickCheckに渡してくれる。
prop_concatR :: [Int] -> [Int] -> [Int] -> Bool
prop_concatR xs ys zs = xs ++ ys ++ zs == concatR [xs, ys, zs]
prop_concatL :: [Int] -> [Int] -> [Int] -> Bool
prop_concatL xs ys zs = xs ++ ys ++ zs == concatL [xs, ys, zs]
prop_concatL' :: [Int] -> [Int] -> [Int] -> Bool
prop_concatL' xs ys zs = xs ++ ys ++ zs == concatL' [xs, ys, zs]
-- case_でHUnitテストケースを書く。TemplateHaskellがHUnitに渡してくれる。
case_cocatR_n :: Assertion
case_cocatR_n = (concatR [[1,2],[3],[],[4,5]]) @?= [1,2,3,4,5]
case_cocatR_emp :: Assertion
case_cocatR_emp = (concatR []) @?= ([] :: [Int])
case_cocatL_n :: Assertion
case_cocatL_n = (concatL [[1,2],[3],[],[4,5]]) @?= [1,2,3,4,5]
case_cocatL_emp :: Assertion
case_cocatL_emp = (concatL []) @?= ([] :: [Int])
case_cocatL'_n :: Assertion
case_cocatL'_n = (concatL' [[1,2],[3],[],[4,5]]) @?= [1,2,3,4,5]
case_cocatL'_emp :: Assertion
case_cocatL'_emp = (concatL' []) @?= ([] :: [Int])
-- 以下はtest-frameworkを使う前に書いたもの。メモのため残しておく。
-- HUnitで複数のTestを実行する関数を定義
runTests :: [Test] -> IO Counts
runTests ts = runTestTT $ TestList ts
-- Test.Frameworkを使わないときはこれらテストケースをmainからrunTests concatTestsを実行
concatTests :: [Test]
concatTests = map TestCase
[ assertEqual "concatR [[1,2],[3],[],[4,5]] " [1,2,3,4,5] (concatR [[1,2],[3],[],[4,5]])
,assertEqual "concatL [[1,2],[3],[],[4,5]] " [1,2,3,4,5] (concatL [[1,2],[3],[],[4,5]])
,assertEqual "concatL' [[1,2],[3],[],[4,5]] " [1,2,3,4,5] (concatL' [[1,2],[3],[],[4,5]])
,assertEqual "concatR [] " ([] :: [Int]) (concatR [])
,assertEqual "concatL [] " ([] :: [Int]) (concatL [])
,assertEqual "concatL' [] " ([] :: [Int]) (concatL' [])
]
\end{code}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment