Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

第17章 2-4节翻译完毕 #149

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ _build/*
*.hi
*.*~
.DS_Store
*.exe
1,045 changes: 1,045 additions & 0 deletions chp/17.rst

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions code/ch17/Enum1.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-- file: ch17/Enum1.hs
{-# LANGUAGE CPP #-}

#define N 16

main = print [ 1 .. N ]

31 changes: 31 additions & 0 deletions code/ch17/PCRE-compile.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
-- file ch17/PCRE-compile.hs

import Foreign hiding (unsafePerformIO)
import Foreign.C.Types
import Foreign.C.String
import Data.ByteString hiding (pack)
import System.IO.Unsafe (unsafePerformIO)

import Regex

foreign import ccall unsafe "pcre.h pcre_compile"
c_pcre_compile :: CString
-> PCREOption
-> Ptr CString
-> Ptr CInt
-> Ptr Word8
-> IO (Ptr PCRE)

compile :: ByteString -> [PCREOption] -> Either String Regex
compile str flags = unsafePerformIO $
useAsCString str $ \pattern -> do
alloca $ \errptr -> do
alloca $ \erroffset -> do
pcre_ptr <- c_pcre_compile pattern (combineOptions flags) errptr erroffset nullPtr
if pcre_ptr == nullPtr
then do
err <- peekCString =<< peek errptr
return (Left err)
else do
reg <- newForeignPtr finalizerFree pcre_ptr -- release with free()
return (Right (Regex reg str))
17 changes: 17 additions & 0 deletions code/ch17/PCRE-compile0.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
-- file ch17/PCRE-compile0.hs

import Foreign
import Foreign.C.Types
import Foreign.C.String
import Regex hiding (PCRE)

type PCRE = ()

foreign import ccall unsafe "pcre.h pcre_compile"
c_pcre_compile :: CString
-> PCREOption
-> Ptr CString
-> Ptr CInt
-> Ptr Word8
-> IO (Ptr PCRE)

2 changes: 2 additions & 0 deletions code/ch17/PCRE-nullary.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
-- file ch17/PCRE-nullary.hs
data PCRE
74 changes: 74 additions & 0 deletions code/ch17/Regex.hsc
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
-- file: ch17/Regex.hsc
{-# LANGUAGE CPP, ForeignFunctionInterface #-}

module Regex where

import Foreign
import Foreign.C.Types
import Data.ByteString (ByteString)

#include <pcre.h>

-- | A type for PCRE compile-time options. These are newtyped CInts,
-- which can be bitwise-or'd together, using '(Data.Bits..|.)'
--
newtype PCREOption = PCREOption { unPCREOption :: CInt }
deriving (Eq,Show)


-- PCRE compile options
#{enum PCREOption, PCREOption
, caseless = PCRE_CASELESS
, dollar_endonly = PCRE_DOLLAR_ENDONLY
, dotall = PCRE_DOTALL
, dupnames = PCRE_DUPNAMES
, extended = PCRE_EXTENDED
, extra = PCRE_EXTRA
, firstline = PCRE_FIRSTLINE
, multiline = PCRE_MULTILINE
, newline_cr = PCRE_NEWLINE_CR
, newline_crlf = PCRE_NEWLINE_CRLF
, newline_lf = PCRE_NEWLINE_LF
, no_auto_capture = PCRE_NO_AUTO_CAPTURE
, ungreedy = PCRE_UNGREEDY
}

-- | Combine a list of options into a single option, using bitwise (.|.)
combineOptions :: [PCREOption] -> PCREOption
combineOptions = PCREOption . foldr ((.|.) . unPCREOption) 0

data PCRE

data Regex = Regex !(ForeignPtr PCRE)
!ByteString
deriving (Eq, Ord, Show)

newtype PCREInfo = PCREInfo { unPCREInfo :: CInt }
deriving (Eq,Show)

#{enum PCREInfo, PCREInfo
, info_options = PCRE_INFO_OPTIONS
, info_size = PCRE_INFO_SIZE
, info_capturecount = PCRE_INFO_CAPTURECOUNT
, info_backrefmax = PCRE_INFO_BACKREFMAX
, info_firstbyte = PCRE_INFO_FIRSTBYTE
, info_firstchar = PCRE_INFO_FIRSTCHAR
, info_firsttable = PCRE_INFO_FIRSTTABLE
, info_lastliteral = PCRE_INFO_LASTLITERAL
, info_nameentrysize = PCRE_INFO_NAMEENTRYSIZE
, info_namecount = PCRE_INFO_NAMECOUNT
, info_nametable = PCRE_INFO_NAMETABLE
, info_studysize = PCRE_INFO_STUDYSIZE
, info_default_tables = PCRE_INFO_DEFAULT_TABLES
, info_okpartial = PCRE_INFO_OKPARTIAL
, info_jchanged = PCRE_INFO_JCHANGED
, info_hascrorlf = PCRE_INFO_HASCRORLF
, info_minlength = PCRE_INFO_MINLENGTH
}

newtype PCREExecOption = PCREExecOption { unPCREExecOption :: CInt }
deriving (Eq,Show)

combineExecOptions :: [PCREExecOption] -> PCREExecOption
combineExecOptions = PCREExecOption . foldr ((.|.) . unPCREExecOption) 0

25 changes: 25 additions & 0 deletions code/ch17/Regex0.hsc
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
-- file: ch17/Regex0.hsc
{-# LANGUAGE CPP, ForeignFunctionInterface #-}

module Regex where

import Foreign
import Foreign.C.Types

#include <pcre.h>

-- | A type for PCRE compile-time options. These are newtyped CInts,
-- which can be bitwise-or'd together, using '(Data.Bits..|.)'
--
newtype PCREOption = PCREOption { unPCREOption :: CInt }
deriving (Eq,Show)

caseless :: PCREOption
caseless = PCREOption #const PCRE_CASELESS

dollar_endonly :: PCREOption
dollar_endonly = PCREOption #const PCRE_DOLLAR_ENDONLY

dotall :: PCREOption
dotall = PCREOption #const PCRE_DOTALL

102 changes: 102 additions & 0 deletions code/ch17/RegexExec.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
-- file ch17/RegexExec.hs

import Foreign hiding (unsafePerformIO)
import Foreign.C.Types
import Foreign.C.String
import Data.ByteString hiding (reverse, pack)
import System.IO.Unsafe (unsafePerformIO)
import Data.ByteString.Internal (toForeignPtr)
import Data.ByteString.Unsafe (unsafeDrop, unsafeTake)

import Regex

foreign import ccall unsafe "pcre.h pcre_compile"
c_pcre_compile :: CString
-> PCREOption
-> Ptr CString
-> Ptr CInt
-> Ptr Word8
-> IO (Ptr PCRE)

compile :: ByteString -> [PCREOption] -> Either String Regex
compile str flags = unsafePerformIO $
useAsCString str $ \pattern -> do
alloca $ \errptr -> do
alloca $ \erroffset -> do
pcre_ptr <- c_pcre_compile pattern (combineOptions flags) errptr erroffset nullPtr
if pcre_ptr == nullPtr
then do
err <- peekCString =<< peek errptr
return (Left err)
else do
reg <- newForeignPtr finalizerFree pcre_ptr -- release with free()
return (Right (Regex reg str))

data PCREExtra

foreign import ccall "pcre.h pcre_exec"
c_pcre_exec :: Ptr PCRE
-> Ptr PCREExtra
-> Ptr Word8
-> CInt
-> CInt
-> PCREExecOption
-> Ptr CInt
-> CInt
-> IO CInt

foreign import ccall "pcre.h pcre_fullinfo"
c_pcre_fullinfo :: Ptr PCRE
-> Ptr PCREExtra
-> PCREInfo
-> Ptr a
-> IO CInt

capturedCount :: Ptr PCRE -> IO Int
capturedCount regex_ptr =
alloca $ \n_ptr -> do
c_pcre_fullinfo regex_ptr nullPtr info_capturecount n_ptr
return . fromIntegral =<< peek (n_ptr :: Ptr CInt)

match :: Regex -> ByteString -> [PCREExecOption] -> Maybe [ByteString]
match (Regex pcre_fp _) subject os = unsafePerformIO $ do
withForeignPtr pcre_fp $ \pcre_ptr -> do
n_capt <- capturedCount pcre_ptr

let ovec_size = (n_capt + 1) * 3
ovec_bytes = ovec_size * sizeOf (undefined :: CInt)

allocaBytes ovec_bytes $ \ovec -> do

let (str_fp, off, len) = toForeignPtr subject
withForeignPtr str_fp $ \cstr -> do
r <- c_pcre_exec
pcre_ptr
nullPtr
(cstr `plusPtr` off)
(fromIntegral len)
0
(combineExecOptions os)
ovec
(fromIntegral ovec_size)

if r < 0
then return Nothing
else let loop n o acc =
if n == r
then return (Just (reverse acc))
else do
i <- peekElemOff ovec o
j <- peekElemOff ovec (o+1)
let s = substring i j subject
loop (n+1) (o+2) (s : acc)
in loop 0 0 []

where
substring :: CInt -> CInt -> ByteString -> ByteString
substring x y _ | x == y = empty
substring a b s = end
where
start = unsafeDrop (fromIntegral a) s
end = unsafeTake (fromIntegral (b-a)) start

13 changes: 13 additions & 0 deletions code/ch17/SimpleFFI.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-- file: ch17/SimpleFFI.hs
{-# LANGUAGE ForeignFunctionInterface #-}

import Foreign
import Foreign.C.Types

foreign import ccall "math.h sin"
c_sin :: CDouble -> CDouble

fastsin :: Double -> Double
fastsin x = realToFrac (c_sin (realToFrac x))

main = mapM_ (print . fastsin) [0/10, 1/10 .. 10/10]
26 changes: 25 additions & 1 deletion convention.rst
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,34 @@

功能依赖 functional dependency

第十七章
--------

产生 yield

终结器 finalizer

可重入 reentrant

编译指示 pragma

解引用 dereference

类型化的 typed

空元 nullary

托管的指针 managed pointer

空结尾 null-terminated

单子化的 monadic


第十八章
----------

monad变换器 monad transformer
monad变换器 monad transformer

monad栈 monad transformer stack / monad stack

Expand Down
1 change: 1 addition & 0 deletions index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Real World Haskell 中文版
chp/14
chp/15
chp/16
chp/17
chp/18
chp/19
chp/20
Expand Down