07

24

[Haskell] 頻出関数

2013.07.24(21:51)

[Haskell] 頻出関数
このソースを読むとリスト処理などの勘が取り戻せる。
{-# OPTIONS -Wall -Werror #-}
-- | idiom.hs 頻出関数
module Idiom where
import Test.HUnit
import Test.QuickCheck
--import Data.List (isPrefixOf,isInfixOf,isSuffixOf,group)
import Data.List --(isPrefixOf,isInfixOf,isSuffixOf,group)
import Data.Char (isSpace,toUpper)
-----------------------------------------------------------
-- | 可逆圧縮
encode :: Eq a => [a]->[(Int,a)]
encode = map (\xs -> (length xs,head xs)) . group

decode :: Eq a => [(Int,a)]->[a]
decode = concatMap $ uncurry replicate
-----------------------------------------------------------
-- | ユニットテスト
idiomTest :: Test
idiomTest = test [
    -- | enumFromTo :: Enum a => a -> a -> [a]
    enumFromTo (2::Int) 4  ~=?  [2..4],
    -- | concatMap :: (a -> [b]) -> [a] -> [b]
    concatMap (enumFromTo 1) ([1,3,5]::[Int])  ~=? [1,1,2,3,1,2,3,4,5],
    concatMap (\x -> [(x,x+2,x/2)]) ([1,3,5]::[Float])  ~=? [(1.0,3.0,0.5),(3.0,5.0,1.5),(5.0,7.0,2.5)],
    -- | replicate :: Int->a->[a]  -- n回aを繰り返したリストを返す
    replicate 3 'a'  ~=? "aaa",
    -- | iterate::(a->a)->a->[a]   -- 初期値に関数を繰り返し適用したリストを返す
    (take 10 $ iterate (*2) 1) ~=? ([1,2,4,8,16,32,64,128,256,512]::[Int]),
    -- | fromInteger :: Num a => Integer -> a  -- IntegerとIntに
    ((fromInteger 10)::Int) ~=? (10::Int),
    foldr (+) 0 ([1,2,3]::[Int]) ~=? 6,
    -- | break :: (a -> Bool) -> [a] -> ([a], [a])
    -- | 初めてTrueになるまでと、なった後を分けてタプルで返す
    break (>3) ([1,2,3,4,1,2,3,4]::[Int]) ~=? ([1,2,3],[4,1,2,3,4]),
    takeWhile (< 3) ([1,2,3,4,1,2,3,4]::[Int]) ~=? [1,2],
    dropWhile (< 3) ([1,2,3,4,1,2,3,4]::[Int]) ~=? [3,4,1,2,3,4],
    span (< 3) ([1,2,3,4,1,2,3,4]::[Int]) ~=? ([1,2],[3,4,1,2,3,4]),
    -- | splitAt :: Int -> [a] -> ([a], [a])
    splitAt 3 "abcdef" ~=?  ("abc","def"),
    splitAt 2 "abcde" ~=?  ("ab","cde"),

    -- | filter :: (a -> Bool) -> [a] -> [a]
    filter (\x -> x `mod` 3 == 0) ([1..10]::[Int]) ~=? [3,6,9],
    -- | partition :: (a -> Bool) -> [a] -> ([a], [a])
    partition (\x -> x `mod` 3 == 0) ([1..10]::[Int]) ~=? ([3,6,9],[1,2,4,5,7,8,10]),
    -- | group :: Eq a => [a] -> [[a]]
    group "Mississippi" ~=? ["M","i","ss","i","ss","i","pp","i"],
      
    -- | (!!) :: [a] -> Int -> a -- リストのn番目
    "abc" !! 2 ~=? 'c',
    -- | elem :: Eq a => a -> [a] -> Bool -- 要素がリストに含まれるときTrue
    elem (3::Int) ([1,2,3]::[Int]) ~=? True,
    -- | concat :: [[a]] -> [a] -- リストのリストをリストに均す
    concat ["abc","def"] ~=? "abcdef",
    -- | zip :: [a] -> [b] -> [(a, b)]  -- 2つのリストを貼り合わせてタプルのリストに
    zip ([0..]::[Int]) "abc" ~=? [(0,'a'),(1,'b'),(2,'c')],
    -- | unzip :: [(a, b)] -> ([a], [b]) -- 
    unzip ([(0,'a'),(1,'b'),(2,'c')]::[(Int,Char)]) ~=? ([0,1,2],"abc"),
    -- | zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
    zipWith (+) ([1,2,3]::[Int]) ([4,5,6]::[Int]) ~=? [5,7,9],
    -- | fst :: (a, b) -> a
    fst (1::Int,2::Int)  ~=? 1,
    snd (1::Int,2::Int)  ~=? 2,
    -- | curry :: ((a, b) -> c) -> a -> b -> c
    curry fst (1::Int) (2::Int)  ~=? 1,
    -- | uncurry :: (a -> b -> c) -> (a, b) -> c
    uncurry (+) ((1,2)::(Int,Int))  ~=? 3,
    uncurry (++) ("abc","def")  ~=? "abcdef",
    -- | Data.List ---------------------------------------------------------------
    -- | リストの先頭にリストが現れるときTrue
    isPrefixOf "ab" "abc" ~=? True,
    -- | リストの途中にリストが現れるときTrue
    -- | isInfixOf :: Eq a => [a] -> [a] -> Bool
    isInfixOf "bc" "abcde" ~=? True,
    -- | リストの最後にリストが現れるときTrue
    isSuffixOf "de" "abcde" ~=? True,
    -- | Data.Char ---------------------------------------------------------------
    dropWhile isSpace "\t\r\n\f  abc" ~=? "abc",
    True ~=? True
  ]


convertTest :: Test
convertTest = test [
    -- | Stringを何かに変換する
    (read "5"::Int) ~=? 5,
    (read "5"::Float) ~=? 5.0,
    (read "[1,2,3]"::[Int]) ~=? [1,2,3],
    (read "(1,'a')"::(Int,Char)) ~=? (1,'a'),
    words " a b c "  ~=? ["a","b","c"],
    -- | [String]を何かに変換する
    unwords ["a","b","c"]  ~=? "a b c",
    map (map toUpper) ["abc","def"] ~=? ["ABC","DEF"],
    map (read::String->Int) ["123","456"]  ~=? [123,456],
    -- | Intを何かに変換する
    show (123::Int) ~=? "123",
    -- | fromInteger :: Num a => Integer -> a
    ((fromInteger 123)::Float) ~=? (123.0::Float),
    -- | fromIntegral :: (Integral a, Num b) => a -> b
    -- | [Int]を何かに変換する
    ((map fromInteger [1,2,3]::[Int])::[Int]) ~=? [1,2,3],
    ((map fromInteger [1,2,3]::[Float])::[Float]) ~=? [1.0,2.0,3.0],
    ((map show [(1::Int),2,3])::[String]) ~=? ["1","2","3"],
    True ~=? True
  ]

encodeDecodeTest :: Test
encodeDecodeTest = test [
    [] ~?= encode "",
    [(1,'a')] ~?= encode "a",
    [(1,'M'),(1,'i'),(2,'s'),(1,'i'),(2,'s'),(1,'i'),(2,'p'),(1,'i')] ~?= encode "Mississippi",
    "Mississippi" ~?= decode [(1,'M'),(1,'i'),(2,'s'),(1,'i'),(2,'s'),(1,'i'),(2,'p'),(1,'i')],
    True ~=? True
  ]

-- | encode decode test
prop_encodeDecode :: Eq a => [a] -> Bool
prop_encodeDecode xs = (decode $ encode xs) == xs

---------------------------------------------------
main :: IO ()
main = do
    _ <- runTestTT idiomTest
    _ <- runTestTT convertTest
    _ <- runTestTT encodeDecodeTest
    quickCheck (prop_encodeDecode :: [Int] -> Bool)
    quickCheck (prop_encodeDecode :: [Bool] -> Bool)
    quickCheck (prop_encodeDecode :: [Char] -> Bool)
    putStrLn "done"

プロフィール

島敏博

Shima Toshihiro 島敏博
信州アルプスハイランド在住。HaskellとElixirが好き。組み込みソフトウェアアーキテクト、C++プログラマ、山歩き、美術館巡り、和食食べ歩き、日本赤十字社救急法指導員、インデックス投資、クラシック音楽、SESSAME会員、状態マシン設計、モデル駆動開発、ソフトウェアプロダクトライン、Rubyist、実践ビジネス英語

■ ツイッター
http://twitter.com/saltheads
■ Facebook
http://www.facebook.com/saltheads
■ Qiita
http://qiita.com/saltheads

印刷する場合は、ブラウザの印刷メニューではなく、このページの上から3cmくらいの青いところにある、「印刷」を押してみてください。少しうまく印刷できます。まだ完全ではないのですが、これで勘弁してください。


カテゴリ
最新記事
月別アーカイブ
最新コメント
検索フォーム
リンク
sessame
RSSリンクの表示