Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

List-based Monadic Computations for Dynamically Typed Languages (Python version)

14,839 views

Published on

This presentation explains how to construct list-based monads for dynamically typed languages, with examples in Python.

Published in: Software
  • You have to choose carefully. ⇒ www.HelpWriting.net ⇐ offers a professional writing service. I highly recommend them. The papers are delivered on time and customers are their first priority. This is their website: ⇒ www.HelpWriting.net ⇐
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Welcome to the Illuminate brotherhood were riches and powers are achieved. Having you looking for a way to join the great brotherhood here is a golden opportunity and chance to join the great fraternity. Join Illuminate brotherhood today and receive the sum of $100,000USD immediately after your initiation and more benefits to come your way, No human sacrifices involve only few items needed for your initiation, if interested whats-app the temple lord on for +1 (706) 871-4571 more information and how to be initiated.
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Am here to appreciate Dr Aba for using his herbal medicine to cure my Herpes virus. since 3 years now I have been living with this virus and it has been giving me challenges, I was so perplexed cause i have been taking several drugs to be cured but all of my effort was in vain,one morning i was browsing through the internet then i saw several testimonies about Dr. Aba curing people from Herpes virus and immediately i contacted Dr. Aba on his email: dr.abaherbalhome@gmail.com, i told him about my troubles and he told me that i must be cured, gave me some instructions and which i rightly followed. so he prepared a herbal medicine for me and sent it to me which i used for 2 weeks and everything was like a dream to me and my Herpes virus was totally gone, why don't you contact him today and be free from your diseases because he is very good and honest Doctor. contact him via email; dr.abaherbalhome@gmail.com or whatsApp him on +2348107155060  
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Hi, am Kate Clancy from Norway. i just got my ex husband back through the help of Dr Unity love spells Experts. My husband left me for another woman, This was just 2 years of our marriage. The most painful thing is that I was pregnant with our second baby. I wanted him back. I did everything within my reach to bring him back but all was in vain, I wanted him back so badly because of the love I had for him, I begged him with everything, I made promises but he refused. I explained my problem to my friend and she suggested that I should rather contact a spell caster that could help me cast a spell to bring him back , I had no choice than to try it. I messaged the spell caster called dr unity, and he assured me there was no problem and that everything will be okay before 11 hours. He cast the spell and surprisingly 11 hours later my husband called me. I was so surprised, I answered the call and all he said was that he was so sorry for everything that had happened He wanted me to return to him. He also said he loved me so much. I was so happy and went to him that was how we started living together happily again.thanks to dr unity . if you are here and your Lover is turning you down, or your husband moved to another woman, do not cry anymore, contact Dr.Unity for help now..Here his contact, WhatsApp him: +2348055361568 {or} Email him at: Unityspelltemple@gmail.com ,his website:https://unityspells.blogspot.com .
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here
  • Hello! I do no use writing service very often, only when I really have problems. But this one, I like best of all. The team of writers operates very quickly. It's called ⇒ www.WritePaper.info ⇐ Hope this helps!
       Reply 
    Are you sure you want to  Yes  No
    Your message goes here

List-based Monadic Computations for Dynamically Typed Languages (Python version)

  1. 1. List-based Monadic Computations for Dynamically Typed Languages Wim Vanderbauwhede School of Computing Science, University of Glasgow, UK
  2. 2. Overview Program Composition in Dynamically Typed Languages Objects Monads Defining Karma Karmic Types Combining Functions using Functions The Rules Designing Karma Syntactic Sugar fold and chain Karma Needs Dynamic Typing Karmic Computations By Example Maybe State Parsing Conclusion
  3. 3. Dynamically Typed Languages size proportional to √ #projects on GitHub
  4. 4. Program Composition Most Dynamic Languages use an OOP approach to structure/compose programs But what if you don’t like object orientation? Or what if it is simply not the best approach? An alternative approach to program composition: Functional Languages use composition of higher-order functions In particular, Haskell uses monads ...
  5. 5. Haskell ... Most empathically not dynamically typed ... Makes easy things hard ... But I like Haskell (*ducks*)
  6. 6. Monads a reputation of being esoteric hard to understand the province of academic languages (unknown poet, 21st century) Monas Hieroglyphica, (“The Hieroglyphic Monad”), John Dee, Antwerp 1564
  7. 7. Monads in Dynamic Languages Have been done many times for many languages https://en.wikipedia.org/wiki/Monad(functional_programming)#Monads_in_other_languages But have not found widespread adoption So ...
  8. 8. The Claim ... are monads of practical use in day-to-day programming? Yes! Only we won’t call them monads ...
  9. 9. Karmic Computations Karma is a Sanskrit word meaning action, work or deed. A different approach from the many existing implementations of monads in dynamic languages. Based on types, lambda functions and higher-order functions.
  10. 10. Types and Notation Haskell-style syntax for types: A function g from a type a to a type b: g :: a → b A function s with two arguments and the result of type a: s :: a → a → a A function f from a type a to a type m b, i.e. a type m parametrised on a type b: f :: a → m b A function h which takes as arguments two functions of type a → b and b → c and returns a function of type a → m b: h :: (a → b) → (b → c) → (a → m b)
  11. 11. Lambda Functions Also knows as anonymous subroutines, i.e. functions without a name. They are expressions that can be assigned to variables. Language Lambda Syntax Haskell x y -> f x y LiveScript (x,y) -> f x,y Perl sub ($x,$y) { f $x,$y } Python lambda x,y : f(x,y) Ruby lambda { |x,y| f(x,y) }
  12. 12. Higher-Order Functions Functions that take other functions as arguments and/or return functions as results Available in your favourite dynamically type language: Perl, Ruby, Python, LiveScript, JavaScript, ...
  13. 13. What is Karma? A karmic computation consists of: a given type m a; the higher-order functions bind and wrap and three rules governing those functions.
  14. 14. Karmic Types A karmic type can be viewed as a “wrapper” around another type. It does not have to have a particular structure, e.g. it can be an object, or a list, or a map, or a function. The key point is that the “karmic” type contains more information than the “bare” type. We will write m a as the karmic type constructor, regardless of the structure of the type. For example, in Python the following function f has a type f :: a → m b, if g has type g :: a → b: def f(x): return m( g(x) )
  15. 15. Combining Functions using Functions The purpose of the karmic computation is to combine functions that operates on karmic types. The bind function composes values of type m a with functions from a to m b: bind :: m a → (a → m b) → m b The wrap function takes a given type a and returns m a: wrap :: a → m a With these two functions we can create expressions that consists of combinations of functions.
  16. 16. The Rules Three rules govern bind and wrap to ensure that the composition is well-behaved: 1. bind (wrap x) f ≡ f x 2. bind m wrap ≡ m 3. bind (bind m f) g ≡ bind m (x -> bind (f x) g) In Python syntax: 1. bind(wrap(x),f) = f(x) 2. bind(m,wrap) = m 3. bind(bind(m,f),g) = bind(m,lambda x: bind(f(x),g))
  17. 17. Syntactic Sugar for Monads In Haskell: No sugar: ex x = x -> (bind (g x) (y -> (f (bind y (z -> wrap z))))) Operator sugar: ex x = g x >‌>= y -> f y >‌>= z -> wrap z Do-notation sugar: ex x = do y <- g x z <- f y wrap z
  18. 18. Syntactic Sugar for Karma Our approach: Use lists to combine computations For example: [ word, maybe parens choice natural, [ symbol ’kind’, symbol ’=’, natural ] ]
  19. 19. Designing Karma Grouping items in lists provides a natural sequencing mechanism, and allows easy nesting. In most dynamic languages, lists us the [...,...] syntax, it’s portable and non-obtrusive. We introduce a chain function to chain computations together. Pass chain a list of functions and it will combine these functions into a single expression.
  20. 20. Preliminary: fold To define chain in terms of bind and wrap, we need the left fold function (foldl). foldl performs a left-to-right reduction of a list via iterative application of a function to an initial value: foldl :: (a → b → a) → a → [b] → [a] A possible implementation e.g. in Python would be def foldl (f, acc, lst): for elt in lst: acc=f(acc,elt) return acc
  21. 21. Defining chain We can now define chain as def chain(fs): lambda x: foldl( bind, wrap(x), fs) Or in Haskell syntax chain fs = x -> foldl (>‌>=) (wrap x) fs
  22. 22. Karma Needs Dynamic Typing The above definition of chain is valid in Haskell, but only if the type signature is chain :: [(a → m a)] → (a → m a) But the type of bind is bind :: m a → (a → m b) → m b the karmic type m b returned by bind does not have to be the same as the karmic type argument m a. every function in the list passed to chain should be allowed to have a different type! This is not allowed in a statically typed language like Haskell, so only the restricted case of functions of type a → m a can be used. However, in a dynamically typed language there is no such restriction, so we can generalise the type signature: chain :: [(ai−1 → m ai )] → (a0 → m aN ) ∀i ∈ 1 .. N
  23. 23. Demonstrating Karma Combining computations that can fail Stateful computation Parser combinators
  24. 24. Combining Fallible Computations (1) Expressing failure A Maybe class class Maybe: def __init__(self,value,status): self.val=value self.ok=status # true or false For convenience: a fail instance fail = Maybe(nil,False) Assume f, g, h :: a → Maybe b
  25. 25. Combining Fallible Computations (2) Without karma v1 = f(x) if (v1.ok): v2=g(v1.val) if (v2.ok): v3 = h(v2.val) if (v3.ok): v3.val else: fail else: fail else: fail With karma: comp = chain [ f,g,h ] v1=comp(x)
  26. 26. bind and wrap for Maybe For the Maybe karmic type, bind is defined as: def bind(x,f): if x.ok: f(x) else: fail and wrap as: def wrap(x): Maybe(x,True)
  27. 27. Stateful Computation Using karma to perform stateful computations without actual mutable state. Example in LiveScript, because LiveScript has the option to force immutable variables. There is a growing interest in the use of immutable state in other dynamic languages, in particular for web programming, because immutable state greatly simplifies concurrent programming and improves testability of code.
  28. 28. State Concept and API We simulate state by combining functions that transform the state, and applying the resulting function to an initial state (approach borrowed from Haskell’s Control.State). A small API to allow the functions in the list to access a shared state: get = -> ( (s) -> [s, s] ) put = (s) -> ( -> [[],s]) The get function reads the state, the put function writes an updated state. Both return lambda functions. A top-level function to apply the stateful computation to an initial state: res = evalState comp, init where evalState = (comp,init) -> comp!(init)
  29. 29. Trivial Interpreter: Instructions We want to interpret a list of instructions of type type Instr = (String, ([Int] → Int, [a])) For example instrs = [ ["v1",[set,[1]]], ["v2",[add,["v1",2]]], ["v2",[mul,["v2","v2"]]], ["v1",[add,["v1","v2"]]], ["v3",[mul,["v1","v2"]]] ] where add, mul and set are functions of type [Int] → Int The interpreter should return the final values for all variables. The interpreter will need a context for the variables, we use a simple map { String : Int } to store the values for each variable. This constitutes the state of the computation.
  30. 30. Trivial Interpreter: the Karmic Function We write a function interpret_instr_st :: Instr → [[a], Ctxt]: interpret_instr_st = (instr) -> chain( [ get, (ctxt) -> [v,res] = interpret_instr(instr, ctxt) put (insert v, res, ctxt) ] ) interpret_instr_st gets the context from the state, uses it to compute the instruction, updates the context using the insert function and puts the context back in the state.
  31. 31. Trivial Interpreter: the Stateless Function Using Ctxt as the type of the context, the type of interpret_instr is interpret_instr :: Instr → Ctxt → (String, Int) and the implementation is straightforward: interpret_instr = (instr, ctxt) -> [v,rhs] = instr # unpacking [op,args] = rhs # unpacking vals = map (‘get_val‘ ctxt), args [v, op vals] get_val looks up the value of a variable in the context; it is backticked into an operator here to allow partial application.
  32. 32. bind and wrap for State For the State karmic type, bind is defined as: bind = (f,g) -> (st) -> [x,st_] = f st (g x) st_ and wrap as wrap = (x) -> ( (s) -> [x,s] )
  33. 33. modify: Modifying the State The pattern of calling get to get the state, then computing using the state and then updating the state using put is very common. So we combine it in a function called modify: modify = (f) -> chain( [ get, (s) -> put( f(s)) ] ) Using modify we can rewrite interpret_instr_st as interpret_instr_st = (instr) -> modify (ctxt) -> [v,res] = interpret_instr(instr, ctxt) insert v, res, ctxt
  34. 34. mapM: a Dynamic chain We could in principle use chain to write a list of computations on each instruction: chain [ interpret_instr_st instrs[0], interpret_instr_st instrs[1], interpret_instr_st instrs[2], ... ] but clearly this is not practical as it is entirely static. Instead, we use a monadic variant of the map function, mapM: mapM :: Monad m ⇒ (a → m b) → [a] → m [b] mapM applies the computations to the list of instructions (using map) and then folds the resulting list using bind. With mapM, we can simply write : res = evalState (mapM interpret_instr_st, instrs), {}
  35. 35. Fortran ... I like Fortran (*ducks*)
  36. 36. Parser Combinators Or more precisely, I needed to parse Fortran for source transformations. So I needed a Fortran parser ... ... in Perl (for reasons). So I created a Perl version of Haskell’s Parsec parser combinator library ... ... using Karma.
  37. 37. Parser Combinator Basics Each basic parser returns a function which operates on a string and returns a result. Parser :: String → Result The result is a tuple containing the status, the remaining string and the substring(s) matched by the parser. type Result = (Status, String, [Match]) To create a complete parser, the basic parsers are combined using combinators. A combinator takes a list of parsers and returns a parsing function similar to the basic parsers: combinator :: [Parser] → Parser
  38. 38. Karmic Parser Combinators For example, a parser for a Fortran-95 type declaration: parser = chain [ identifier, maybe parens choice natural, [ symbol ’kind’, symbol ’=’, natural ] ]; In dynamic languages the actual chain combinator can be implicit, i.e. a bare list will result in calling of chain on the list. For statically typed languages this is of course not possible as all elements in a list must have the same type.
  39. 39. bind and wrap for Parser For the Parser karmic type, bind is defined as (Python): def bind(t, p): (st_,r_,ms_) = t if st_ : (st,r,ms) = p(r_) if st: [1,r,ms_+ms] else: [0,r,None] else: [0,r_,None] and wrap as: def wrap(str): [1,str,None]
  40. 40. bind and wrap for Parser For the Parser karmic type, bind is defined as (LiveScript): bind = (t, p) -> [st_,r_,ms_] = t if st_ then [st,r,ms] = p r_ if st then [1,r,ms_ ++ ms] else [0,r,void] else [0,r_,void] and wrap as: wrap = (str) -> [1,str,void]
  41. 41. Final Example (1) Parsers can combine several other parsers, and can be labeled: f95_arg_decl_parser = chain [ whiteSpace, {TypeTup => type_parser}, maybe [ comma, dim_parser ], maybe [ comma, intent_parser ], symbol ’::’, {Vars => sepBy ’,’,word} ]
  42. 42. Final Example (2) We can run this parser e.g. var_decl = "real(8), dimension(0:ip,-1:jp+1,kp) :: u,v" res = run( f95_arg_decl_parser, var_decl ) This results in the parse tree: { ’TypeTup’ => { ’Type’ => ’real’, ’Kind’ => ’8’ }, ’Dim’ => [’0:ip’,’-1:jp+1’,’kp’], ’Vars’ => [’u’,’v’] }
  43. 43. Parser Combinators Library The Python version is on GitLab: https://gitlab.com/wim_v12e/parser-combinators-py The Perl and LiveScript versions are on GitHub: https: //github.com/wimvanderbauwhede/Perl-Parser-Combinators https: //github.com/wimvanderbauwhede/parser-combinators-ls The Perl library is actually used in a Fortran source compiler https://github.com/wimvanderbauwhede/RefactorF4Acc
  44. 44. Conclusion We have presented a design for list-based monadic computations, which we call karmic computations. Karmic computations are equivalent to monadic computations in statically typed languages such as Haskell, but rely essentially on dynamic typing through the use of heterogeneous lists. The proposed list-based syntax is easy to use, results in concise, elegant and very readable code, and is largely language-independent. The proposed approach can be applied very widely, especially as a design technique for libraries.
  45. 45. Thank you

×