æ©ããã®ã§ãä»å¹´ã12æ25æ¥ã¨ãªãã¾ãããã¡ãªã¼ã¯ãªã¹ãã¹ï¼ ãã¡ã®ã¡ã³ã£åæªç£ãã¡ãããµã³ã¿ããã«æ¸ããæç´éããã¬ã´ãããã£ã¦ãæºæ¦ã®ããã§ãã
ããã¦ä»æ¥ã¯ãHaskell Advent Calendar 2013 ã®æçµæ¥ã§ãããã¾ãã
Haskellãããï¼
ãç´ç²ãªã³ã¼ãã§æ§æããã®ã Haskell ãããããã°ã©ã ã§ãããIOã¯Haskellããããªããã¨ããçºè¨ãããè³ã«ãã¾ãã
確ãã«ãå½ä»¤ããã°ã©ãã³ã°ã®ä¸çããé¢æ°ããã°ã©ãã³ã°ã®ä¸çã«ãã£ã¦ããã¨ãããã
- ä¸å¤ãã¼ã¿ã使ã£ãæ°¸ç¶ãã¼ã¿ããã°ã©ãã³ã°
- é¨åããã°ã©ãã³ã°
- ç´ç²ãªã³ã¼ãã«å¯¾ããæ§è³ªãã¹ã
ãªã©ã«ã¯ãè¡æãåãããã¨ã§ãããã
ã§ããç´ç²ãªã³ã¼ãã¯ãHaskell ã®ä¸çã®ååã§ããããã¾ãããããã¯ãã³ã³ãã¤ã©ã¼ã¨ããä¿è·è ã«å®ãããæªæå¹´ã®ä¸çã§ããSimon Peyton Jones ããã®è¨èãåããã°ã象çã®å¡ã®ä¸ã¨ãè¨ããã§ãããã
象çã®å¡ã®å¤ãè¦ãã«ã¯ãIO ã®ä¸çã«è¸ã¿åºãå¿ è¦ãããã¾ããããã¦ãIO ãã¾ã Haskell ã§ããIO ã®ä¸çã§ã¯ãå½ä»¤ããã°ã©ãã³ã°ã®ããã«ãã¼ã¿ãç ´å£ã§ããããã«ãªãã¾ãã以ä¸ã«ãä¾ã示ãã¾ãã
- IORef ãæãå (ãã¼ã¿)ãå¤ãããã
- å¯å¤ãª IOArray ã使ããããã£ã¦ãå¤æ´å¯è½ãªããã·ã¥ãã¼ãã«ã使ãã
- FFI ãå©ç¨ã㦠C ã©ã¤ãã©ãªãã·ã¹ãã ã³ã¼ã«ãå¼ã³åºãã
ããã«ãIO ã®ä¸çã§ã¯ä¸¦è¡(cocurrent)ããã°ã©ãã³ã°ãå¯è½ã§ãã
- forkIO ã«ãã軽éã¹ã¬ããã®çæ
- MVar ã«ãã軽éã¹ã¬ããéã®åæã¨éä¿¡
- STM ã«ãããããããã¯ã®åé¿
èªå·±è²¬ä»»ã§ãã大人ã®ä¸çã«ãããããããã®è¨äºã§ã¯ãHaskellãåå®å ¨ãªCã¨ãã¦ä½¿ããã¡ã¢ãªã¼ãæä½ããæ¹æ³ã«ã¤ãã¦èª¬æãã¾ãã
ãã¤ã³ã¿ã¼
åã Haskell ãããç¨åº¦åããããã«ãªã£ãããã®ãã¨ã§ããSystem.Posix.IOãçºãã¦ãã¦ãfdReadBuf ã fdWriteBuf ã¨ããé¢æ°ãè¦ã¤ãã¾ããããããã®é¢æ°ã¯ã以ä¸ã®ãããªåãæã£ã¦ãã¾ãã
fdReadBuf :: Fd -> Ptr Word8 -> ByteCount -> IO ByteCount fdWriteBuf :: Fd -> Ptr Word8 -> ByteCount -> IO ByteCount
ååã示ãããã«ãããã¯ãããããã¡ã¤ã«ãããããã¡ã¼(ä¸å®ã®ã¡ã¢ãªã¼é å)ã«ãã¼ã¿ãèªã¿è¾¼ãã ãããããã¡ã¼ãããã¡ã¤ã«ã¸ãã¼ã¿ãæ¸ãè¾¼ãã ãããé¢æ°ã§ããç¥èã足ããªãã£ãå½æã®åã¯ãPtr Word8 ããããã¡ã¼ãæå³ãã¦ãããã¨ã¯æ¨æ¸¬ã§ãã¾ããããã©ããã£ã¦ä½¿ã£ããããã®ãåããã¾ããã§ããã
ã¾ã Word8 ã§ãããããã¯8ãããã®ç¬¦å·ãªãæ´æ°ãæå³ãã¦ãã¾ããã¤ã¾ãããã¤ãã®ãã¨ã§ããã¡ãªã¿ã«ãHaskell ã§ã¯ Int ã符å·ããã®æ´æ°ãWord ã符å·ãªãã®æ´æ°ã§ãããã®å¾ã®æ°åã¯ããããæ°ã表ãã¾ããWord8 ãªã©ã¯ãData.Word ã§å®ç¾©ããã¦ãã¾ãã
Ptr ã¯æåéãããã¤ã³ã¿ã¼ãForeign.Ptr ã§å®ç¾©ããã¦ãã¾ãã
ãã£ã¦ãPtr Word8 ã¯ãã¤ãã¸ã®ãã¤ã³ã¿ã¼ã®ãã¨ã§ããC ã§æ¸ããªã unsigned char * ã«ç¸å½ãã¾ãã
å·éã«èããã¨ãããã¡ã¼ã確ä¿ããé¢æ°ããåããã°ããã®äºã¤ã®é¢æ°ã使ã£ã¦ãã¡ã¤ã«ãã³ãã¼ããããã°ã©ã ãæ¸ãããã§ããããããåå¿è ã«ã¯ãã®é¢æ°ãè¦ã¤ããã®ãé£ããã§ãããããªããªããForeign.Ptr ãæ¢ãã¦ããããããé¢æ°ã¯åå¨ããªãããã§ãã
å¿ è¦ãªé¢æ°ãè¤æ°ã®ã¢ã¸ã¥ã¼ã«ã«æ£ãã°ã£ã¦ãããããããHaskell ã§ã®ãã¤ã³ã¿ã¼ããã°ã©ãã³ã°ãåããã«ããã¦ããæ大ã®åå ã§ãã
ãã¡ã¤ã«ã®ã³ãã¼
ãããã¡ã¼ã確ä¿ããé¢æ°ã¯ Foreign.Marshal.Alloc ã§å®ç¾©ããã¦ãã¾ããããããªã®ç¥ããï¼ãã£ã¦æãã§ãããããã¨ãã°ã以ä¸ã®é¢æ°ã使ãã¾ãã
allocaBytes :: Int -> (Ptr a -> IO b) -> IO b
ãã㯠OO ã®ä¸çã§è¨ããã¼ã³ãã¿ã¼ã³ã§ããããããã¡ã¤ã«ãã³ãã¼ããããã°ã©ã ãæ¸ããã§ãããããã¨ãã°ã以ä¸ã®ããã«ãªãã¾ãã
module Main where import Control.Monad (when) import Foreign.Marshal.Alloc (allocaBytes) import Foreign.Ptr (Ptr) import System.Environment (getArgs) import System.Posix.IO (OpenMode(..)) import qualified System.Posix.IO as IO import System.Posix.Types (Fd) import Data.Word (Word8) type Buffer = Ptr Word8 bufSize :: Int bufSize = 4096 main :: IO () main = do [src,dst] <- getArgs from <- IO.openFd src ReadOnly Nothing IO.defaultFileFlags to <- IO.openFd dst WriteOnly (Just 0o644) IO.defaultFileFlags copy from to IO.closeFd from IO.closeFd to copy :: Fd -> Fd -> IO () copy from to = allocaBytes bufSize loop where siz = fromIntegral bufSize loop :: Buffer -> IO () loop ptr = do n <- IO.fdReadBuf from ptr siz when (n /= 0) $ do IO.fdWriteBuf to ptr n loop ptr
ã¡ã¢ãªã¼ãæ¸ãæãã
次ã«ãèªåã§ç´æ¥ã¡ã¢ãªã¼ãæ¸ãæãã¦ã¿ã¾ãããããã¨ãã°ãã³ãã¼ããã¤ãã§ã«ã·ã¼ã¶ã¼æå·ããããæ°å¤ã3å¢ããã¦ã¿ã¾ããããã
Ptr ãæãã¡ã¢ãªã¼ã«å¤ãæ¸ãè¾¼ãã«ã¯ãããã¾ããç¥ããï¼ãã¨ãæãã§ãããForeign.Storable ã® poke ã使ãã¾ããèªã¿è¾¼ãã¨ã㯠peek ã§ãã(BASIC ã¿ããã§ããï¼)
以ä¸ã« peek 㨠poke ã®åã示ãã¾ãã
poke :: Storable a => Ptr a -> a -> IO () peek :: Storable a => Ptr a -> IO a
Storable ã¯ããã¼ã¿ããã¤ãåã«ã·ãªã¢ã©ã¤ãºããããã®åã¯ã©ã¹ã§ããããã©ã«ã㧠Word8 㯠Storable ã®ã¤ã³ã¹ã¿ã³ã¹ã«ãªã£ã¦ãã¾ããWord8 ãã·ãªã¢ã©ã¤ãºããã¨ãåã«1ãã¤ãã§ããããWord8 ã®å¤ã poke ããã°ä¸ãã¤ãæ¸ãè¾¼ãããã¨ã«ãªãã¾ãã
ãããã¡ã¼å ¨ä½ãèµ°æ»ããã«ã¯ããã¤ã³ã¿ã¼ã®å¤ãå¢ãããªãã¨ããã¾ãããããã«ã¯ Foreign.Ptr ã® plusPtr ã使ãã¾ãã
plusPtr :: Ptr a -> Int -> Ptr b
Haskell ã§ã¯åºæ¬çã«å¤æ°ã«åä»£å ¥ã§ãã¾ãããããC ã®ããã«æ°è»½ã« p++ ãªã©ã¨ã¯ã§ãã¾ãããé¢æ°ã«å¼æ°ã«ãplusPtr ããå¤ã渡ããªã©ã®å·¥å¤«ãå¿ è¦ã§ããã§ã¯ãã³ã¼ããæ¸ãã¦ã¿ã¾ãããã
module Main where import Control.Monad (when) import Foreign.Marshal.Alloc (allocaBytes) import Foreign.Ptr (Ptr, plusPtr) import System.Environment (getArgs) import System.Posix.IO (OpenMode(..)) import qualified System.Posix.IO as IO import System.Posix.Types (Fd) import Data.Word (Word8) import Foreign.Storable (peek, poke) type Buffer = Ptr Word8 bufSize :: Int bufSize = 4096 main :: IO () main = do [src,dst] <- getArgs from <- IO.openFd src ReadOnly Nothing IO.defaultFileFlags to <- IO.openFd dst WriteOnly (Just 0o644) IO.defaultFileFlags copy from to IO.closeFd from IO.closeFd to copy :: Fd -> Fd -> IO () copy from to = allocaBytes bufSize loop where siz = fromIntegral bufSize loop :: Buffer -> IO () loop ptr = do n <- IO.fdReadBuf from ptr siz encrypt ptr (fromIntegral n) when (n /= 0) $ do IO.fdWriteBuf to ptr n loop ptr encrypt :: Buffer -> Int -> IO () encrypt _ 0 = return () encrypt ptr n = do c <- peek ptr poke ptr (c + 3) encrypt (ptr `plusPtr` 1) (n - 1)
ãããã¡ã¼ã®å¢çãå®ãã®ã¯ãèªå·±è²¬ä»»ã§ãããããããæ°ãä»ãã¦ã
ç· ã
ãã¤ã³ã¿ã¼ããã°ã©ãã³ã°ã®ã¨ã£ãããã¨ãã¦ã¯ãååãªãã¨ãåãã£ãã¨æãã¾ãããã²ãHaskell ã§ã®ä½ã¬ãã«ãªããã°ã©ãã³ã°ã«ãææ¦ãã¦ã¿ã¦ä¸ããã
ããã§ã¯ããããå¹´ãï¼