Haskell 将值求解为弱头范式 weak head normal form (WHNF),即一个可以被匹配的值,有三种情况:
是一个常数,如 1
有一个顶级构造,如 False、Just (1+1)、0:filter f xs
是一个函数,如 (\x -> 1+x)
注:
表达式的类不是 WHNF
如果一个函数跟着参数,也不是 WHNF,必须能够模式匹配
当给一个名字值的时候,这个值被分享 share 了,如
f :: Int -> Int f i = if i>10then10else i _______shared________ | | f (1+1) ==> if (1+1)>10then10else (1+1) ==> if2>10then10else2 ==> ifFalsethen10else2 ==> 2
自动分享等价表达式是一种叫 公共子表达式删除 Common Subexpression Elimination (CSE) 的优化
和懒惰结合起来,即一个名称最多计算一次
(||) :: Bool -> Bool -> Bool True || _ = True _ || x = x
可以看出,|| 强制左边的参数,即对它的左参数严格 strict in its left argument
所以
even :: Int -> Bool even x = x == 0 || not (even (x-1)) -- 可行
foldl'Int :: (Int -> Int -> Int) -> Int -> [Int] -> Int foldl'Int f z [] = z foldl'Int f 0 (x:xs) = foldl'Int f (f 0 x) xs foldl'Int f z (x:xs) = foldl'Int f (f z x) xs
classMonad m where (>>=) :: m a -> (a -> m b) -> m b -- 把一个正常值变成 monad return :: a -> m a -- 更简单的链接 (>>) :: m a -> m b -> m b a >> b = a >>= \_ -> b -- 即忽略了前者参数的 >>=
Maybe 是 monad:
instanceMonadMaybewhere (Just x) >>= k = k x Nothing >>= _ = Nothing
-- 由默认定义可以看出,>> 可以不用写 (Just _) >> k = k Nothing >> _ = Nothing
return x = Just x
do 的返回
这是用 monad 写的
f = op1 >>= \x -> op2 >> op3 >>= \y -> op4 >> op5 x y
这是用 do 写的
f = do x <- op1 op2 y <- op3 op4 op5 x y
可以观察到,do 就是 monad 和 lambda 的一种语法,两者一一对应
do x <- op a ~~~> op a >>= \x -> do ... do op a ~~~> op a >> do ... dolet x = expr ~~~> let x = expr indo ... do finalOp ~~~> finalOp
monad 的一个实例
import Control.Monad
dataLogger a = Logger [String] a derivingShow
msg :: String -> Logger () msg s = Logger [s] ()
-- The Functor instance just maps over the stored value instanceFunctorLoggerwhere fmap f (Logger log x) = Logger log (f x)
-- This is an Applicative instance that works for any -- monad, you can just ignore it for now. We'll get back -- to Applicative later. instanceApplicativeLoggerwhere pure = return (<*>) = ap
-- Finally, the Monad instance instanceMonadLoggerwhere return x = Logger [] x Logger la a >>= f = Logger (la++lb) b -- 连接两个 monad 时会合并 msg,保留第二个值 whereLogger lb b = f a
State Monad
dataState s a = State (s -> (a,s))
runState (State f) s = f s
-- 覆盖 state 的操作 (并生成 ()) put :: s -> State s () put state = State (\oldState -> ((),state))
-- 生成当前 state 的操作 get :: State s s get = State (\state -> (state,state))
-- 用一个函数修改 state 的操作 (并生成 ()) modify :: (s -> s) -> State s () modify f = State (\state -> ((), f state))
-- Functor and Applicative instances skipped
instanceMonad (States) where return x = State (\s -> (x,s))
op >>= f = State h where h state0 = let (val,state1) = runState op state0 op2 = f val in runState op2 state1
Prelude> import Database.SQLite.Simple PreludeDatabase.SQLite.Simple> :t open open :: String -> IOConnection PreludeDatabase.SQLite.Simple> db <- open "example.sqlite"
-- 数据库查询 PreludeDatabase.SQLite.Simple> importqualified Data.Text as T PreludeDatabase.SQLite.SimpleT> q = Query (T.pack "SELECT 1;") PreludeDatabase.SQLite.SimpleT> res <- query_ db q :: IO [[Int]] PreludeDatabase.SQLite.SimpleT> res
classFunctor f => Applicative f where pure :: a -> f a liftA2 :: (a -> b -> c) -> f a -> f b -> f c
可以看出,Applicative 类介于 Functor 和 Monad 之间
liftA2 接受两个值,而不是 fmap :: (a -> b) -> f a -> f b 接受一个值
对于 Maybe 的实例
instanceApplicativeMaybewhere pure x = Just x liftA2 f (Just x) (Just y) = Just (f x y) liftA2 f _ _ = Nothing
列表 Applicative
instanceApplicative [] where pure x = [x] liftA2 f xs ys = [f x y | x <- xs, y <- ys]
新的操作符
<$> 是 fmap 的前缀版本
(<$>) :: Functor f => (a -> b) -> f a -> f b f <$> x = fmap f x not <$> JustTrue ==> JustFalse
<*> 是 applicative 版本的函数应用
(<*>) :: Applicative f => f (a -> b) -> f a -> f b Just not <*> JustTrue ==> JustFalse
两者组合:
say :: String -> Int -> String -> String say x i y = x ++ " has " ++ show i ++ " " ++ y say <$> Just"haskell" <*> Just99 <*> Just"operators" ==> Just"haskell has 99 operators"
另外两个操作符
(*>) :: Applicative f => f a -> f b -> f b x *> y = liftA2 (\a b -> b) x y
(<*) :: Applicative f => f a -> f b -> f a x <* y = liftA2 (\a b -> a) x y
意思是两个操作都执行,但是只保留一个结果
Validation Applicative
Validation 用于收集错误信息
dataValidation a = Ok a | Errors [String] deriving (Show,Eq)
mapM (\x -> if x>=0thenJust x elseNothing) [1,2,3] ==> Just [1,2,3]
Applicative 的等价函数是 traverse,是类 Traversable 的成员
traverse :: (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
Traversable
class (Functort, Foldablet) => Traversable t where traverse :: Applicative f => (a -> f b) -> t a -> f (t b) mapM :: Monad m => (a -> m b) -> t a -> m (t b)
处理失败:Alternative
classApplicative f => Alternative f where empty :: f a -- 没有结果 (<|>) :: f a -> f a -> f a -- 结合结果
Monads and Applicatives
如果一个 Applicative 同时是一个 Monad,则
pure === return
fmap === liftM
fmap f op === do x <- op return (f x)
liftA2 === liftM2
liftA2 f op1 op2 === do x <- op1 y <- op2 return (f x y)
-- Public constructor function for Input, only allows constructing -- Unsafe Inputs from Strings. makeInput :: String -> InputUnsafe makeInput xs = Input xs
-- Adds comment to the database. addForumComment :: InputSafe -> IOResult addForumComment = ...
-- We can combine inputs, but that won't change their safety concatInputs :: Input a -> Input a -> Input a concatInputs (Input xs) (Input ys) = Input (xs++ys)
-- Strip bad characters to turn an unsafe input safe escapeInput :: InputUnsafe -> InputSafe escapeInput (Input xs) = Input (filter (\c -> isAlpha c || isSpace c) xs)