资源说明:
#Tackling the Awkward Squad ###21 Sept 2011 Moderator: Ben Karel Notetaker: Nick Canzoneri ##Opening discussion up with questions about the paper Q: Why use monads when you can use Haskell for pure functional stuff and interface for other stuff Sub question: Difficulty of interfacing? A: Still not that hard to write imperative code and foreign function interface (FFI) is still monadic Values from IO are still tainted with IO. Anything returned from the IO Monad is still typed with IO Imperative programming in Haskell: actions are first class values. Building actions up (using them as a first class function) doesn't have side effects, can build them up and only on execution get side effects The programmer can use actions to make it easier to constrain scope of side effects. For example, writing compiler - transform one thing to another, need to choose fresh names without reuse, choosing that name is a side effect. Q: Difference between action and a first class function (like in Scala or other language)? A: Action is a particular typed function - returns a value in a monad You can tell a lot about the program from the types, even monadic types. IOMonad and STM Monad provides information to the programmer. (STM == software transactional memory) Could (probably) write monads in any language. Haskell gives you permanence so you can't cheat when writing monadic code and also the primitives to make it easier, such as with IO. ```haskell >>= --is pronounced bind ``` The do notation is much easier to read, but just uses bind under the scenes. That is why in Haskell, opposed to other languages, it's easer to accomplish monadic tasks. Other languages would have to use straight up bind or the user would have to re-implement the do notation again. Intuition of monad = way of enforcing order in a lazy language - not only way to think about it, but a very good way return in Haskell - not like return in other languages: return in Haskell means "rewrap this output in the monad" Going to the Haskell interpreter: ```haskell :t return 1 -- :t in the interpreter prints out the type signature return 1 :: (Num t, Monad m) => m t :t return 'c' return 'c' :: (Monad m) => m Char --Equivalent Java to above == mwhere m extends Monad ``` Q: Interfacing Haskell with impure program? A: One of first examples, with Haskell calling C wrapper to read files. The naive implementation uses a request/response model when calling out to the C wrapper. Calling it, with lazy language, those calls to the C wrapper can came back out of order. That's why monads were invented. Bind (>>=) - Guarantees machine state happens in the order you expect Haskell runtime written in C, functions exposed to Haskell programmer that sleep the thread, this is what enforces ordering in some cases. Trying to decide how the Haskell runtime runs a Haskell program is causing some confusion, it is easier to say that the Haskell code describes the program and we don't need to worry so much about how the program is run. When we use constructs like monads, that is what allows us to be assured that the runtime is going to do the right thing. Haskell accept - takes socket to listen on, and returns an tuple of (handle, peer, port) in a monad ##Section 3, Semantics ###Evaluation Contexts Labelled transitions an attempt to formalize the system. Transitions that are labeled are ones that interact with the outside world, transitions are the things that are changing state either into or out of the world. Defining these transitions allows evaluation of the program as simplifying the equation. For your language to interact with the world need to expand your picture, to things in the world. Any nondeterministic function you can't predict, but if you specify at each point the transitions that the function has to go through, you can reason enough about it. Eugenio Moggi paper, [Notion of Computation and monads](http://www.cs.cmu.edu/~crary/819-f09/Moggi91.pdf)- written about monads in terms of semantics, not in any practical terms Insight - can use operational semantics to perform optimizations and PROVE that the end results are the same, so you need to prove the IO and unsafe things in such a way to perform those optimizations. Need formal rules to say when two different looking programs are the same. ##Section 4.1 Defines the main loop of a web server ```haskell acceptConnections :: Config -> socket -> IO () - io unit ``` Will run forever, accepts a socket and forks ```haskell forever = a >> forever a ``` Where a is an action and >> is similar to bind but doesn't return a value, just guarantees that you call a and then forever a in order. Monads are not limited to IO, you could say that monads might be equivalent to interfaces in Java bind for the IO monad is a primitive You can define bind for other types that don't have to a primitive and can be lazy. bind only enforces sequential behavior in the IO monad ##Implementing non IO monads in Haskell ```haskell instance monad [] where return a = [a] xs >>= f = concat (map f xs) --type signatures: xs :: [X] -- xs is list of X f :: (X -> [S]) -- function f goes from X to list of S xs >>= f :: [S] map f xs :: [[S]] ``` ###Maybe monads: ```haskell data Maybe a = Nothing | Just a ``` Maybe a is either value nothing or value a ```haskell instance Monad Maybe where return a = Just a (>>=) :: Maybe a -> (a -> Maybe b) -> Maybe b -- bind has type function from maybe a to function from a to maybe b to maybe b Nothing >>= f = Nothing (Just a) >>= f = (f a) ``` ###Using the maybe monad ```haskell --standard implementation maybeGetInt :: Maybe Int getTwoInts :: Maybe (Int, Int) getTwoInts = maybeGetInt >>= \i1 -> maybeGetInt >>= \i2 -> return (i1, i2) --getTwoInts formatted showing nested lambdas getTwoInts = maybeGetInt >>= \i1 -> maybeGetInt >>= \i2 -> return (i1, i2) --using explicit bind function and code reformatted maybeGetInt :: Maybe Int getTwoInts :: Maybe (Int, Int) getTwoInts = let bind = (>>=) in let g = (\i2 -> return (i1, i2)) in let f = (\i1 -> bind maybeGetInt g) in bind maybeGetInt f --using the maybe monad in a do block --much easier maybeGetInt :: Maybe Int getTwoInts :: Maybe (Int, Int) getTwoInts = do { i1 <- maybeGetInt i2 <- mabyeGetInt return (i1, i2) } ``` ##Talking about "World" ```haskell type IO a = World -> (a, World) ``` It is nonsense, something real that really shouldn't be exposed to the person. It's a (false) abstraction to formalize writing functional code Anything could really cause side effects in there real world i.e., temperature of computer For us "side effect free", means that programmer can't directly influence the world, programmer can't assign variables Comment that Haskell has similar problem as Perl in that syntax can change a lot and mean the same thing Next paper is [The Zippers](http://www.st.cs.uni-saarland.de/edu/seminare/2005/advanced-fp/docs/huet-zipper.pdf)
本源码包内暂不包含可直接显示的源代码文件,请下载源码包。