Haskell Tips (æååç·¨)
ãã®è¨äºã¯Haskell Advent 2012ã®ããã®è¨äºã§ãã(é ãã¦ããã¾ãã(ã½Â´Ï`))
Haskellã§å®éã«ããã°ã©ã ãæ¸ãä¸ã§ã¯ãæ§ã ãªããã±ã¼ã¸ã«ããåãé¢æ°ãå©ç¨ããã®ãä¸å¯é¿ã«ãªãã¾ãã ãããã£ã便å©ãã¼ã«ã®ãã¡æååã¾ããã«ã¤ãã¦èª¿ã¹ãã¨ããããHaskellæè¿å§ããã£ã¦äººã«ç´¹ä»ããã®ããã®è¨äºã®ç®çã§ããHaskell詳ããæ¹ã«ã¯æ°ããçºè¦ã¯ç¡ãããããã¾ãããããããªããã
ãã®è¨äºã§ã¯ã主ã«æååã«ç¦ç¹ãå½ã¦ã¦ãã¾ããããã®ãã¡ã¾ãå¥ã®ãã¼ãã§ãæ¸ããã¨æã£ã¦ãã¾ãã
ãªããåæã¨ãã¦ããã¼ã¸ã§ã³ã¯Haskell Platform 2012.4.0.0ã¨ãããã«ä»éããGHCãããã±ã¼ã¸ã§ãã OSããMac OS XãLinuxãªã©UNIXç³»ã®ç°å¢ãæ³å®ãã¦ãã¾ããWindowsã¯æã£ã¦ã¾ããã®ã§ãããã¾ãããããããªããã
æåå
Haskellã§ã¯æååã®è¡¨ç¾ãè²ã ãã£ã¦ãHaskellãå§ããã°ããã®äººã¯ãã£ã¨æ··ä¹±ããã§ãããã èªåã大混乱ãã¾ãããã
Haskellã§æååãæ±ãã®ã«ãã使ãããåã¯å¤§ããåãã¦ä»¥ä¸ã®ï¼ã¤ã§ãã
- String
- ByteString
- Strict
- Lazy
- Text
- Strict
- Lazy
ByteStringåã¯bytestringããã±ã¼ã¸ã§ãTextã¯textããã±ã¼ã¸ããæä¾ããã¦ã¾ãã ã©ã¡ããHaskell Platformã«åå°ããã¦ã¾ãã
ã²ã¨ã¾ã確èªãã¦è¡ãã¾ãããã
String
ããã¾ã説æã¯è¦ããªãã¨æãã¾ãããStringã¯ãã ã®æååCharã®ãªã¹ãã§ãã ãªã®ã§lengthãmapãªã©ã®ãªã¹ãæä½é¢æ°ã¯ãã®ã¾ãã¾ä½¿ãã¦ä¾¿å©ã§ãããèªç¶ãªçºæ³ã§ãã
Stringã§ã¯ä¸æåã§ï¼ã¯ã¼ããå ããã®ã§ã ã¡ã¢ãªãå°ãã¾ãããé度ãã¤ãã¤ãã§ãã
ã§ãStringã¯ãã«ããã¤ãæåãæ±ãã¾ãã 以ä¸ã®ãããªãã®ã¯ã©ã³ã¿ã¤ã ã®ãã±ã¼ã«ãèæ ®ãã¦ãæ£ããåºåãããã¯ãã§ãã
putStrLn "鬼"
ãããããå
¥åºåã®ã¨ã³ã³ã¼ãã£ã³ã°ãªã©ã®ãã±ã¼ã«æ
å ±ã¯ãGHC.IO.Encodingã¢ã¸ã¥ã¼ã«ã®
getLocaleEncoding
ãgetLocaleFileSystemEncoding
ã§åå¾ã§ãã¾ãã
import GHC.IO.Encoding sample1 :: IO () sample1 = print =<< getLocaleEncoding
åºå
UTF-8
ä»ã«ãGHC.IO.Encodingã«ã¯ã¨ã³ã³ã¼ãã£ã³ã°ãè¨å®ããæ©è½ãªã©ããããããªã®ã§ããã®æ©è½ãå¿ è¦ãããããããã¾ããã
ByteString
ããããHaskellãããRead World Haskellããªã©ãèªã¾ããæ¹ã¯ããªãã¿ãã¨æãã¾ããbytestringããã±ã¼ã¸ã§æä¾ããã¦ããByteStringåã¨é¢æ°ã§ãå¹çè¯ãæååï¼ã¨ãããããã¤ãåï¼ãæ±ããã¨ãã§ãã¾ãã
ByteStringãå®éã«åãã¦ãããã¼ã¿ã¯Word8(8bitã®ç¬¦å·ãªãæ´æ°)åãªã®ã§ããããã大ããè¦ç´ ãåãããã¨ããã¨åé¡ãããã¾ãããã«ããã¤ãæåãªã©8bitã«åã¾ããªããã¼ã¿ãããã§ãã
ByteStringã«ã¯ãå®ã¯ååã®ï¼ã¤ã®åãããã¾ãã ã²ã¨ã¤ã¯Data.ByteString.Internalã¢ã¸ã¥ã¼ã«ã§å®ç¾©ããã¦ããæ£æ ¼è©ä¾¡ã®ByteStringã§ã ããã²ã¨ã¤ã¯Data.ByteString.Lazy.Internalã¢ã¸ã¥ã¼ã«ã«ããé 延è©ä¾¡ã®ByteStringã§ãã å é¨çã«ã¯ãLazyãªæ¹ã®ByteStringã¯ãStrictã®ByteStringããªã¹ãã«ãã¦ããã ãã§ãã
-- LazyãªByteStringã®å®ç¾© import qualified Data.ByteString.Internal as S data ByteString = Empty | Chunk {-# UNPACK #-} !S.ByteString ByteString
æ£æ ¼ã¨é 延ã®åãåé¢ã ãè¦ã¦çµã¿åããããã¨ãã¦ããåã¨ã©ã¼ãåºãã®ã§æ°ãã¤ãã¾ããã(ï½ï½¥Ï・´) å¤é¨ã®ã©ã¤ãã©ãªã使ãã¨ãã¯ãByteStringã¨ã ãæ¸ãã¦ãã£ã¦ãã©ã¡ããåãããªãã®ã§ãã½ã¼ã¹ãèªããªããHTMLçã®Haddockã®ãªã³ã¯å ã確èªãããªãããªãã¨ããã¾ãããã
ãããããããã®åã®ç¸äºå¤æã¯ã©ãããã®ãã¨ããã¨ãbytestringããã±ã¼ã¸ã®ãã¼ã¸ã§ã³0.10.0.1ã§ã¯ã
toStrict
ã¨fromStrict
ããLazyã¨Strictãç¸äºå¤æããããã®é¢æ°ãå®ç¾©ããã¦ãã¾ãã
ãã以åã®ãã¼ã¸ã§ã³ã§ã¯ããããã®é¢æ°ã¯èªä½ãããã¨ã«ãªãã¾ãã
ãã®ã¸ãã®è©±ã¯ä»¥ä¸ã®ãªã³ã¯ãåèã«ãã¦ä¸ããã
- Convert a Lazy ByteString to a strict ByteString
- Proposal: Add {to,from}Strict conversion functions between strict and lazy ByteStrings
ä»ã«ãData.ByteStringã«ã¯ã¢ã¸ã¥ã¼ã«åã®æ«å°¾ã«Char8ãã¤ãData.ByteString.Char8ã¨Data.ByteString.Lazy.Char8ãããã¾ããããããã¯ByteStringãå é¨ã§ãã¤Word8ã®ãã¼ã¿ã¨Charã®ç¸äºå¤æããã¦ãããé¢æ°ãéã«ãã¾ãã¦ããã ããªã®ã§ãæ¬è³ªçã«ã¯ä½ãå¤ããã¾ãããå¤æã®åã®ãªã¼ãã¼ãããã¯ããããã§ããã
ãã®ã¸ãã®æåãã¡ãã£ã¨è¦ã¦ã¿ã¾ãããã
ä¸ã®ã³ã¼ãã®é ã«ããOverloadedStrings
ã¯ãæååãªãã©ã«ãIsString
åã¯ã©ã¹ã®ã¤ã³ã¹ã¿ã³ã¹ã¸ã¨èªåçã«å¤æãã¦ããã¾ãã
ã§ãã®ã§ãæååãªãã©ã«ã«é¢ãã¦ã¯ãbytestringãtextããã±ã¼ã¸ã§ç¨æããã¦ããpack
é¢æ°ãæ示çã«å¼ã¶å¿
è¦ã¯ããã¾ããã
ã³ã¡ã³ãã§ã¯æåã«å¯¾å¿ããæå符å·åå½¢å¼ã®ã³ã¼ããæ¸ãã¦ãã¾ãã
{-# LANGUAGE OverloadedStrings #-} import qualified Data.ByteString.Char8 as B8 sample :: IO () sample = do -- '鬼': -- UTF-16: 9B3C -- UTF-8: E9ACBC -- '<': -- ASCII: 3C B8.putStrLn (B8.singleton '鬼') -- 'å¹³': -- UTF-16: 5E73 -- UTF-8: E5B9B3 -- 's': -- ASCII: 73 B8.putStrLn (B8.singleton 'å¹³') B8.putStrLn (B8.pack "鬼平") B8.putStrLn "鬼平" -- OverloadedStringsããªããã°ããã®æ¸ãæ¹ã¯åã¨ã©ã¼
åºå
<
s
<s
<s
æ¼¢åãªã©ãã«ããã¤ãæåã¯ãCharåã¨ãã¦ã®æåãªãã©ã«ã§ã¯UTF-16ã§ã¨ã³ã³ã¼ãããã¦ããæ§åã§ãã ããããByteStringã¯å é¨çã«ã¯Word8(8bit)åä½ã§ããæ±ããªãã®ã§ã ByteStringã«å¤æããéã«ãCharã®ãã¼ã¿ã¯Word8(8bit)ã«åãè©°ãããã¦ãã®ãåããã¨æãã¾ãã
æååãªãã©ã«ã§æå®ããããã«ããã¤ãæåãç¡çããByteStringã§æ±ããã¨ããã¨ãç¹ã«ã¨ã©ã¼ãåºããééã£ãçµæãè¿ãã®ã§æ³¨æãå¿ è¦ã§ããã ãªã®ã§ãByteStringã¯æååã¨ããããã¯ãçã®ãã¤ãåãåãããã¼ã¿åã¨æã£ãã»ããè¯ãã¨æãã¾ãã
IOãä»ããªã©ãã¦å¤é¨ããä¸ãããããã«ããã¤ãæåã¯ã ã¨ã³ã³ã¼ãã£ã³ã°ãªã©èæ ®ãããã«ãã®ã¾ã¾ãã¤ãåã¨ãã¦æ±ãã¾ãã ãªã®ã§ã以ä¸ã®ããã«ã¦ã¼ã¶ã¼ã®å ¥åãåãåãå ´åã¯ãå ¥åããã«ããã¤ãæåãå«ãã§ãã¦ãåé¡ããã¾ãããå ¥åããã®ã¾ã¾åãã¦ãã ãã§ãã
sample :: IO () sample = do putStrLn "What is your name?" putStr "> " name <- B8.getLine B8.putStrLn $ "Hello, " `B8.append` name putStrLn $ (show $ B8.length name) ++ "-byte"
åºå
What is your name?
> 鬼平
Hello, 鬼平
6-byte
ãã¤ãæ°ãUTF-8ã§ã¨ã³ã³ã¼ãããã¨ãã«ããã6ãã¤ãã«ãªã£ã¡ãã£ã¦ã¾ããã ããã§ã¯æåæ°ã¯æ£ããæ°ãããã¾ããããæåå¢çãåãããªãã®ã§grepã®ãããªãã¨ãåºæ¥ã¾ããã
Text
ããããããã£ããã«ããã¤ãæåããã¤ãåã§ãªããã¡ããã¨æååã¨ãã¦æ±ãã«ã¯ã©ãããã°ããã®ãã¨è¨ãã¨ãtextã¨ããããã±ã¼ã¸ãããã¾ãã¦ãããã¤ã使ãã¨ããããã§ãã
ã¡ããã¨æååã¨ãã¦æ±ãã¨ã¯ãæååã®é·ããæ£ããæ°ããããã¨ããç¹å®ã®æåãæ¢ããã¨ããããã話ã§ãã
textããã±ã¼ã¸ã§ã¯ãæååæä½ã®ããã®ã¢ã¸ã¥ã¼ã«ã¨IOã®ããã®ã¢ã¸ã¥ã¼ã«ãå¥ã®ã¢ã¸ã¥ã¼ã«(Data.Text.IO)ã«ããã¾ããä¸ã®ããã«ãåãT
ã¨ããå¥åãã¤ãã¦importããã¨æ¥½ã¡ãã§ãã
{-# LANGUAGE OverloadedStrings #-} import qualified Data.Text as T import qualified Data.Text.IO as T sample :: IO () sample = do T.putStrLn (T.singleton '鬼') T.putStrLn (T.singleton 'å¹³') T.putStrLn (T.pack "鬼平") T.putStrLn "鬼平" -- ãããOverloadedStringsãå¿ è¦
åºå
鬼
å¹³
鬼平
鬼平
è¯ãæãã§ãã(´Ïï½) Data.Text.IOã§ã¯ãã±ã¼ã«ãèæ ®ãã¦ããã¦ãã¾ãã
å ã»ã©ã®ByteStringã®ã¨ãã¨åããµã³ãã«ããTextãªã大ä¸å¤«ã§ãã
sample :: IO () sample = do putStrLn "What is your name?" putStr "> " name <- T.getLine T.putStrLn $ "Hello, " `T.append` name putStrLn $ (show $ T.length name) ++ "-letter"
åºå
What is your name?
> 鬼平
Hello, 鬼平
2-letter
ã¡ããã¨æåæ°ãæ°ãã¦ãã¾ãããã¤ãæ°ãããªãã£ã¦ã ã§ããTextã®lengthé¢æ°ã®è¨ç®éã¯O(n)ã§ã(´ã»Ïã»ï½)
Data.Text.IOã«ã¯ä»ã«ãã¡ã¤ã«ãHandleã¨Textåã®ãã¼ã¿ãããåãããé¢æ°ãç¨æããã¦ã¾ãã
Textã¯ByteStringã¨ã®ç¸äºå¤æãå¯è½ã§ãããLazyãªãã¼ã¸ã§ã³ãããã¾ãã
ç¸äºå¤æã«å¿
è¦ãªé¢æ°ã¯Data.Text.Encoding
ã¢ã¸ã¥ã¼ã«ã«ããã¾ãã
å©ç¨ã§ããã¨ã³ã³ã¼ãã£ã³ã°ã¯ä»¥ä¸ã®ï¼ã¤ã§ãã
ä¸ã®ä¾ã§ã¯ããã«ããã¤ãæåãByteStringã§è¡¨ç¾ãã¦ãdecodeç³»ã®é¢æ°ããã®ByteStringãããªããªå°ã£ã¦Textã«ã¬ã¬ãã¨å¤æãã¦ããã¾ãã
ã¡ãªã¿ã«ãä»»æã®ãã¤ãåãä½æãããæã¯ã
以ä¸ã®æ§ã«æååãªãã©ã«ã®ä¸ã§ããã¯ã¹ã©ãã·ã¥()ã¨16é²æ°ã表ãx
ã§æå®ãããã¨ãã§ãã¾ãã
10é²æ°ã§ã¯ãx
ã¯è¦ãã¾ããã
{-# LANGUAGE OverloadedStrings #-} import qualified Data.ByteString as B import qualified Data.Text as T import qualified Data.Text.IO as T import qualified Data.Text.Encoding as T import qualified Data.Text.Encoding.Error as T sample :: IO () sample = do -- '鬼': -- UTF-8: E9ACBC -- UTF-16: 9B3C let oniUTF8 = "\xE9\xAC\xBC" :: B.ByteString oniUTF16BE = "\x9B\x3C" :: B.ByteString -- ããã°ã¨ã³ãã£ã¢ã³ oniUTF16LE = "\x3C\x9B" :: B.ByteString -- ãªããªã¨ã³ãã£ã¢ã³ T.putStrLn $ T.decodeUtf8 oniUTF8 -- Output: 鬼 T.putStrLn $ T.decodeUtf16BE oniUTF16BE -- Output: 鬼 T.putStrLn $ T.decodeUtf16LE oniUTF16LE -- Output: 鬼 -- ã¨ã³ãã£ã¢ã³ã®ééã!! T.putStrLn $ T.decodeUtf16LE oniUTF16BE -- Output: ã²
UTF-8ã§ã¯ãã¤ããªã¼ãã¼ã®æå®ã¯ä¸è¦ãªã®ã§ããã UTF-16ã§ã¯å¿ è¦ã§ããã¤ããªã¼ãã¼ãééããã¨å¥ã®æåã¨ãã¦èªèããã¦ããã¾ãã¾ãã å¤é¨ããåãåã£ãUTF-16ã§ã¨ã³ã³ã¼ãããã¦ããã¯ãã®ByteStringãªã©ããTextåã«å¤æããéã¯ãã¤ããªã¼ãã¼ã«æ°ãã¤ãã¾ãããã
ãã¨ãå¤é¨ããåãåã£ããã¼ã¿ãªã©ãTextåã«è½ã¨ãããéã«ã¯æ°ãã¤ããªããã°ãªããªããã¨ãããã¾ãã
以ä¸ã®ä¾ã¯ä¾å¤ãæãã¦ãã¾ãã¾ãã
T.decodeUtf16BE "\xD8\x00"
åºå
"*** Exception: Cannot decode input: Data.Text.Encoding.Fusion.streamUtf16BE: Invalid UTF-16BE stream
ããã¯ãTextåãå
é¨çã«ã¯UTF-16ãå©ç¨ãã¦ãããã¨ãåå ã§ãã
Unicodeã§ã¯U+D800~U+DBFFã¨U+DC00~U+DFFFã®ç¯å²ã®16bitããã¢(ãµãã²ã¼ããã¢)ã«ãã¦ã16bitã ãã§ã¯è¡¨ç¾ããããªãæåã表ç¾ãã¦ãã¾ãã
ãã®ç¯å²ã¯UTF-16ã§ã¯è¡¨ç¾ããããªãã®ã§ãdecodeUtf16BE
ãªã©ã§ã¯ä¾å¤ãæãã¾ãã
å¤é¨ããä¸ããããByteStringããã³ã¼ãããã¨ãã¯ããã®æåã«æ³¨æãã¦ä¾å¤ãæ¾ããã
decodeUtf16BEWith
é¢æ°ãªã©ããã³ã¼ãã®ã¨ã©ã¼ãçããæã®æåãæ示ããé¢æ°ã使ãã¨ããã§ãããã
lenientDecodeã使ãã¨ããã³ã¼ãã§ããªããã®ã¯ã³ã¼ããã¤ã³ãU+FFFDã«ç½®ãæãããã¾ãã
T.putStrLn $ T.decodeUtf16BEWith T.lenientDecode "\xD8\x00"
ä»ã«ãUTF-8ã«éãã°utf8-stringã¨ããããã±ã¼ã¸ãããããã§ããã使ã£ããã¨ã¯ããã¾ããã®ã§åããã¾ãã(ã½Â´Ï`)
blaze-builder
ãã£ã³ã¯ã®ãµã¤ãºã...
ByteStringã®èª¬æã®ã¨ããã§ãLazyãªByteStringã¯StrictãªByteStringã®ãªã¹ãã ã¨èª¬æãã¾ããã ã ã¨ããã¨ãç´°ããä½ã£ãStrictãªByteStringãããããã¤ãªãã°LazyãªByteStringãä½ãå ´åãçµå±ç´°ããByteStringãé£ãªã£ããªã¹ããåºæ¥ä¸ããããã§ãã
ä¸ã®ä¾ã§ã¯ã5ãã¤ãã®ByteStringã10åé£çµãã¦ã50ãã¤ãã®LazyãªByteStringãä½ã£ã¦ãã¾ãã ãããã¾ããã£ã³ã¯ã«å解ãã¦ãããããã®é·ãã調ã¹ãã¨ã確ãã«5ãã¤ãã®ãã£ã³ã¯ã10åé£ãªã£ã¦ã¾ãã
{-# LANGUAGE OverloadedStrings #-} import Control.Monad import Data.Monoid import Blaze.ByteString.Builder as B import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Char8 as BS chunkSizes :: BL.ByteString -> [Int] chunkSizes = map BS.length . BL.toChunks concatByteString :: Int -> BS.ByteString -> BL.ByteString concatByteString n = BL.fromChunks . replicate n main = print . chunkSizes $ concatByteString 10 "xxxxx"
åºå
[5,5,5,5,5,5,5,5,5,5]
5ãã¤ããã¤ã®ãã£ã³ã¯ã«ãªã£ã¦ãããããã¡Charã®ãªã¹ãã ã£ãStringã¨å¤§ãã¦å¤ãããã£ã¦ãã¨ã§ã ã²ã¨ã¤ã²ã¨ã¤ã®ãã£ã³ã¯ãµã¤ãºãåºãã¦ããã¾ããã¨Lazyãªãã¤ãã¹ããªã³ã°ãä½ã£ã¦ãããã®ãblaze-builderã§ãã
blaze-builderã§ã¯Builder
åãä»ãã¦æååã®çµåãO(1)ã§è¡ããLazyãªByteStringãåãåºãã¨ãã«å¤§ããªãã£ã³ã¯ãæä¾ãã¦ããã¾ãã
blaze-builderã§æååé£çµããããããblazeConcatByteString
é¢æ°ãå ããä¾ã以ä¸ã®ã³ã¼ãã§ãã
{-# LANGUAGE OverloadedStrings #-} import Control.Monad import Data.Monoid import Blaze.ByteString.Builder as B import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Char8 as BS byteN :: Int -> BS.ByteString byteN n = BS.concat $ replicate n "x" chunkSizes :: BL.ByteString -> [Int] chunkSizes = map BS.length . BL.toChunks concatByteString :: Int -> BS.ByteString -> BL.ByteString concatByteString n = BL.fromChunks . replicate n blazeConcatByteString :: Int -> BS.ByteString -> BL.ByteString blazeConcatByteString n = B.toLazyByteString . mconcat . map B.fromByteString . replicate n main = forM_ [1, 10, 100, 1000, 5000, 10000] $ \x -> do let bs = byteN x putStrLn $ show x ++ "-byte:" putStr "no-blaze " print . chunkSizes $ concatByteString 10 bs putStr "blaze " print . chunkSizes $ blazeConcatByteString 10 bs putStr "\n"
åºå
1-byte:
no-blaze [1,1,1,1,1,1,1,1,1,1]
blaze [10]
10-byte:
no-blaze [10,10,10,10,10,10,10,10,10,10]
blaze [100]
100-byte:
no-blaze [100,100,100,100,100,100,100,100,100,100]
blaze [1000]
1000-byte:
no-blaze [1000,1000,1000,1000,1000,1000,1000,1000,1000,1000]
blaze [4080,5920]
5000-byte:
no-blaze [5000,5000,5000,5000,5000,5000,5000,5000,5000,5000]
blaze [4080,32752,13168]
10000-byte:
no-blaze [10000,10000,10000,10000,10000,10000,10000,10000,10000,10000]
blaze [10000,10000,10000,10000,10000,10000,10000,10000,10000,10000]
blaze-builderã使ã£ã¦ã¤ãªããã»ããããã£ã³ã¯ã®ãµã¤ãºã大ãããªã£ã¦ãé£çµãªã¹ãã®é·ããçããªã£ã¦ã¾ããã ãããã¦ãã£ã³ã¯ã®ãµã¤ãºã大ãããããã¨ã§ããã£ãã·ã¥ã®å©ç¨ãå¹çåããããå ¥åºåã«é¢ããã·ã¹ãã ã³ã¼ã«ã®ãªã¼ãã¼ããããä½æ¸ãã¦ããããã§ãã
詳ãããããã¡å©ç¨ã®æ¦ç¥ãªã©ã«ã¤ãã¦ã¯ãblaze-builderã®haddockãä½è ã®ããã°è¨äºãåèã«ãã¦ä¸ããã
ãããå©ç¨ãã¦ãHTMLãSVGãªã©ãé«éã«æ§ç¯ããblaze-htmlãblaze-svgã¨ãã£ãããã±ã¼ã¸ãããã¾ãã Webã¢ããªã±ã¼ã·ã§ã³ãã¬ã¼ã ã¯ã¼ã¯ã®Yesodãªã©ã§ã使ããã¦ãã¾ããã
ãã³ããã¼ã¯
æå¾ã«ãblaze-builderãã©ããããå¹ãã®ãããã³ããã¼ã¯ãã«ã¸ã¥ã¢ã«ã«åã£ã¦ã¿ã¾ãããï¼
ãã³ããã¼ã¯ã«ã¯criterionã使ã£ã¦ã¾ããHaskellã®ãã³ããã¼ã¯ãç°¡åã«åãã¦ããã©ã¦ã¶ã§è¦ãããåºåãå¾ããã¾ãã
blazeã使ç¨ããªãå ã ã®é£çµæä½ã¨ãblazeãå©ç¨ããé£çµã¨ã®ä¸¡æ¹ã®æ¹éã§æååçãã¤ãªãã¦ããã¡ã¤ã«ã«åºåãã¦ãã¾ãã ã¤ãã§ã«ãTextã«é¢ãã¦ãByteStringã¨åæ§ã«ãã³ããã¼ã¯ãåã£ã¦ã¿ã¾ããã
{-# LANGUAGE OverloadedStrings #-} import Data.Monoid import Blaze.ByteString.Builder as B import Blaze.ByteString.Builder.Char.Utf8 as BT import qualified Data.ByteString.Lazy as BL import qualified Data.ByteString.Char8 as BS import qualified Data.Text as T import qualified Data.Text.Lazy as TL import qualified Data.Text.Lazy.IO as TL import qualified Data.Text.Encoding as T import qualified Data.Text.Lazy.Builder as T import Criterion.Main import System.IO (openTempFile) import System.Directory (removeFile) -- N-byteã®ByteStringãä½ã byteN :: Int -> BS.ByteString byteN n = BS.concat $ replicate n "x" concatByteString :: Int -> BS.ByteString -> BL.ByteString concatByteString n = BL.fromChunks . replicate n blazeConcatByteString :: Int -> BS.ByteString -> BL.ByteString blazeConcatByteString n = B.toLazyByteString . mconcat . map B.fromByteString . replicate n -- N-æåã®Textãä½ã textN :: Int -> T.Text textN n = T.concat $ replicate n "鬼" concatText :: Int -> T.Text -> TL.Text concatText n = TL.fromChunks . replicate n blazeConcatText :: Int -> T.Text -> TL.Text blazeConcatText n = T.toLazyText . mconcat . map T.fromText . replicate n main :: IO () main = do -- åºåç¨ã®ä¸æãã¡ã¤ã« (tmpfile, tmph) <- openTempFile "/tmp" "bench_blaze" -- 1, 10, 50ã®å¤§ããã®åèªãã10000åã¤ãªãã let samples = [1,5,10,50] wc = 10000 defaultMain $ [ bgroup ("[bytestring] " ++ show x ++ "-byte words") [ bench "no-blaze" $ BL.hPut tmph $ concatByteString wc (byteN x) , bench "blaze" $ BL.hPut tmph $ blazeConcatByteString wc (byteN x) ] | x <- samples ] ++ [ bgroup ("[text] " ++ show x ++ "-letter words") [ bench "no-blaze" $ TL.hPutStr tmph $ concatText wc (textN x) , bench "blaze" $ TL.hPutStr tmph $ blazeConcatText wc (textN x) ] | x <- samples ] removeFile tmpfile
ä¸ååãByteStringã§ãä¸ååãTextã§ãã
ã¡ã£ã¡ããæååçã»ã©ãå¹æã大ããããã§ããã
ãã³ããã¼ã¯ã®å®è¡ã¯ä»¥ä¸ã®æ§ãªæãã§ãã
% ghc -O2 bench_blaze.hs % ./bench_blaze -o bench_blaze.html
åºåã¯åãããããã®ããä¸é¨åã£ã¦ã¾ãã
åºå
warming up
estimating clock resolution...
mean is 1.488974 us (640001 iterations)
found 4828 outliers among 639999 samples (0.8%)
3539 (0.6%) high severe
estimating cost of a clock call...
mean is 58.44394 ns (8 iterations)
found 1 outliers among 8 samples (12.5%)
1 (12.5%) high severe
benchmarking [bytestring] 1-byte words/no-blaze
mean: 1.221033 ms, lb 1.214946 ms, ub 1.228679 ms, ci 0.950
std dev: 34.94729 us, lb 29.31052 us, ub 43.71415 us, ci 0.950
benchmarking [bytestring] 1-byte words/blaze
mean: 136.0696 us, lb 125.3679 us, ub 144.9379 us, ci 0.950
std dev: 49.58111 us, lb 39.05003 us, ub 60.22993 us, ci 0.950
benchmarking [bytestring] 5-byte words/no-blaze
mean: 1.321834 ms, lb 1.310183 ms, ub 1.337639 ms, ci 0.950
std dev: 68.97484 us, lb 54.09187 us, ub 95.68489 us, ci 0.950
benchmarking [bytestring] 5-byte words/blaze
mean: 743.6934 us, lb 709.6834 us, ub 775.6366 us, ci 0.950
std dev: 169.3327 us, lb 132.2535 us, ub 223.0841 us, ci 0.950
benchmarking [bytestring] 10-byte words/no-blaze
mean: 1.396986 ms, lb 1.387786 ms, ub 1.408378 ms, ci 0.950
std dev: 52.24961 us, lb 42.96288 us, ub 63.49543 us, ci 0.950
benchmarking [bytestring] 10-byte words/blaze
mean: 1.448711 ms, lb 1.383338 ms, ub 1.513390 ms, ci 0.950
std dev: 331.6004 us, lb 294.9020 us, ub 414.8301 us, ci 0.950
benchmarking [bytestring] 50-byte words/no-blaze
mean: 6.478227 ms, lb 5.424632 ms, ub 7.761446 ms, ci 0.950
std dev: 5.944880 ms, lb 5.028813 ms, ub 7.670362 ms, ci 0.950
benchmarking [bytestring] 50-byte words/blaze
mean: 7.454674 ms, lb 7.041077 ms, ub 8.173508 ms, ci 0.950
std dev: 2.719382 ms, lb 1.760055 ms, ub 5.017425 ms, ci 0.950
benchmarking [text] 1-letter words/no-blaze
mean: 3.269654 ms, lb 3.259670 ms, ub 3.282536 ms, ci 0.950
std dev: 58.06780 us, lb 46.70660 us, ub 75.66644 us, ci 0.950
benchmarking [text] 1-letter words/blaze
mean: 306.1035 us, lb 304.2076 us, ub 308.4018 us, ci 0.950
std dev: 10.65997 us, lb 9.045305 us, ub 12.66282 us, ci 0.950
benchmarking [text] 5-letter words/no-blaze
mean: 4.930164 ms, lb 4.542772 ms, ub 6.752361 ms, ci 0.950
std dev: 3.662762 ms, lb 177.2833 us, ub 8.698922 ms, ci 0.950
benchmarking [text] 5-letter words/blaze
mean: 1.524795 ms, lb 1.515778 ms, ub 1.535984 ms, ci 0.950
std dev: 51.46477 us, lb 43.33059 us, ub 64.69094 us, ci 0.950
benchmarking [text] 10-letter words/no-blaze
mean: 5.897089 ms, lb 5.879782 ms, ub 5.917257 ms, ci 0.950
std dev: 95.94202 us, lb 82.75690 us, ub 114.9103 us, ci 0.950
benchmarking [text] 10-letter words/blaze
mean: 3.982748 ms, lb 3.591212 ms, ub 4.620310 ms, ci 0.950
std dev: 2.510847 ms, lb 1.805720 ms, ub 3.784512 ms, ci 0.950
benchmarking [text] 50-letter words/no-blaze
mean: 21.43716 ms, lb 19.98548 ms, ub 27.01497 ms, ci 0.950
std dev: 13.20911 ms, lb 2.446692 ms, ub 31.00659 ms, ci 0.950
benchmarking [text] 50-letter words/blaze
mean: 21.46007 ms, lb 20.58942 ms, ub 22.80350 ms, ci 0.950
std dev: 5.445815 ms, lb 3.780456 ms, ub 8.059161 ms, ci 0.950
ã¨ããã§ãææ°ã®bytestring-0.10.2.0ã®ããã±ã¼ã¸ãè¦ãã¨ãBuilderé¢ä¿ã®ããã±ã¼ã¸ãbytestringããæä¾ããã¦ã¾ããã ããã¥ã¡ã³ããããµã³ãã«ã³ã¼ããªã©ãããå å®ãã¦ã¾ãã textã§ã¯æ¢ã«Builderãå ¥ã£ã¦ãã¦ã¾ãã
ã¾ã¨ã
ï¼ç¨®ã®æåååã¨é£çµã©ã¤ãã©ãªã®blaze-builderãè¦ã¦ãã¾ããã
- Stringã¯ãã«ããã¤ãæåãæ±ãã¦ã«ã¸ã¥ã¢ã«ã«ä½¿ãããã©é·ãæååã«ã¯åããªãã
- ByteStringã¯æååã¨ãããããã¤ãåã§ãå種ãã¼ã¿ãã·ãªã¢ã©ã¤ãºããã«ã¯ä¾¿å©ãblaze-builderããããã
- Textã¯Stringã®ããã«ãã«ããã¤ãæåãæ±ãã¦ãByteStringã®ããã«å¹çã®ããå¦çãã§ãã¦å¬ããã
ãããã®å®è£ ãHaskellã§æ¸ããã¦ããã®ã§ãã½ã¼ã¹ãèªãã§ã¿ãã°ãã£ã¨é¢ç½ãçºè¦ãããã¨æãã¾ãã(ã»Ï<)ã
ä½ãééããªã©ããã¾ããããTwitterå®@brain_appleãã³ã¡ã³ãæ¬ãªã©ã§æãã¦é ããã¨ãããããã§ãã