Haskell for Computational Quantum Chemistry
Total Page:16
File Type:pdf, Size:1020Kb
Haskell for Computational Quantum Chemistry Felipe Zapata Group of Reactivity and Molecular Structure September 12, 2012 Why on galaxy people use Fortran? “FORTRAN was the language of choice for the same reason that three-legged races are popular”. Ken Thompson, 1983 Turing Award Lecture. If you ask in an academic environment about Fortran is highly probable that you get that... • Since Fortran has been in use for more than fifty years, there is a vast body of Fortran in daily use throughout the scientific and engineering communities. Buddha Says... “Do not believe in anything simply because you have heard it. Do not believe in anything simply because it is spoken and rumoured by many. Do not believe in anything simply because it is found written in your religious books. Do not believe in anything merely on the authority of your teachers and elders. Do not believe in traditions because they have been handed down for many generations. But after observation and analysis, when you find that anything agrees with reason and is conducive to the good and benefit of one and all, then accept it and live up to it.” Why Functional Programming Matters ● “As software becomes more and more complex, it is more and more important to structure it well. Well-structured software is easy to write and to debug, and provides a collection of modules that can be reused to reduce future programming costs” John Hughes Then, Why Haskell? The bloody-hands programmer answer ● Haskell is capable of anything, with enough skill. It is very fast (properly optimized). ● Programming at a high level of abstraction should diminish the amount of opportunities you have to introduce bugs. ● Haskell is most likely quite different from any language you've ever used before. My answer From my perspective humankind do not create only because it can, we create because through our creations we discover the deepest nature of our being. And those complex data structures that we program reflect the complexity of our nature, being Haskell and adequate tool for materialized our thoughts. λ -> Hack your own brain Why bothering about abstract data structure? Computer Science is about computers only as far as Cosmological Science is about telescopes. Edsger W. Dijkstra, Turin award 1971 Immutable Variables In Haskell, a variable is a name for some valid expression. The word "variable" as applied to Haskell variables is misleading, since a given variable's value never varies during a program's runtime. A little about the types Types are the abstract representation of the data that we operate with in the computer Haskell is smart enough 3 :: Int that it can infer the 3.1415 :: Double types, but on the 'h' :: Char contrary of Fortran the True :: Bool “Static Type Declaration” in Haskell is for helping the programmer Some common operators Like most of the language used in Computational Chemistry, Haskell include the basis operators: (+) ,(-),(*), (^),(**) (/) > 3+ 4 = 7 > 2.0 ** 1.5 = 2.8284 and some specific ones like : (rem), (div) > 5 `div` 4 = (div) 5 4 = 1 > 11 `rem` 3 = (rem) 11 3 = 2 List and Tuples “Lists are the bread and butter of Haskell collections” Real World Haskell. [1,2,3,4,5] :: [Int] “Hi quantum world” :: [char] ≡ String [True,False,True] :: [Bool] [1.23,-32.1,1.0/23.1] :: [Double] (6.62606e-34,”Planck's Const” ::(Double,String) ([1,2,3,5,7,11,13,17],True) :: ([Double],Bool) (18,”Agua”, “H2O”) :: (Int,String,String) The fun of functions!! plus x y = x + y Prelude has a big inv x = recip x amount of functions, very common functions power x y = x ** y are there for free!! Lambda Abstraction plus x y = x + y = (\x y → x + y) inv x = recip x = (\x → recip x) power x y = x ** y = (\x y → x ** y) Polymorphism Let's take a look at the type of the previous functions > (+) :: Num a => a -> a -> a > (**) :: Floating a => a -> a -> a mmmmm and these other types: >(/) :: Fractional a => a -> a -> a >(^) :: (Integral b, Num a) => a -> b -> a It we suppose that those “a” are dummy variables and can represent any values, then those “Num a =>” restrict the kind of values that the “a” can represent What is Polymorphism use for ? Let's assume that we defined the (+) operador as : (+) :: Int → Int → int So far so good, but what if we need to defined the sum over the reals?, we need to defined something like: (sumDouble) :: Double → Double → Double So we have to defined a function for every kind of type over we want to operate TypeClasses ● Our previous definition of the (+) operator show us the necessity of defining typeclasses. ● Typeclasses allow some function to behave accordingly to the type over which they are operating. Let's have a Tour for the principal typeclasses in Haskell. We have met the Num class, where inhabit the floating point representation, integrals of arbitrary precision and some exotic fauna. TypeClasses ● The Class show contained those type that can be converted to string and are suitable for printing. print :: Show a => a → IO () ● The Class Read, complementary to Show, defines functions for transforming a string to a type member of the Read Class. read :: Read a => String → a TypeClasses ● The Eq Class contained those types that can be examined for equality. (==) :: Eq a => a -> a -> Bool ● The Ord Class include those types that can sorted. Sort :: Ord a => [a] -> [a] Operations over Lists: play with the structures and let alone the individual data What if we have a list of data and we want to operate a function over the data? Give an opportunity to the map function map :: (a -> b) -> [a] -> [b] > map sin [pi,0.5*pi,2.0*pi] And what if we only want some values that fulfil some condition? filter :: (a -> Bool) -> [a] -> [a] > filter (\x → x `div`2) [1..100] Let's talk about Recursion In Haskell there is not such a thing like “For Loops” then how do we represent then? Mathematical induction can help us to prove the True of a statement P, for an infinite sequence of cases. We proceed as follow : 1. basis. Prove that 0 has the property P. 2. Induction step. Assume the induction hypotheses is that n has the property P. Prove on the basis of this that n+1 has property P. ∀n ∈ ℕ: P(n) Recursion in Haskell We can defined a loop as follow: Basis Case loop :: Double → [Double] → Double loop acc [ ] = acc Induction step loop :: Double → [Double] → Double loop acc (x:xs) = loop (acc + x) xs Folds family Probably when you need to recourse over some data structure, Haskell has a library function that will do it for you, like the beloved folds. The Fold left function has the following type foldl :: (a -> b -> a) -> a -> [b] -> a Let's explore it !! We can defined the function sum as Sum xs = foldl (+) 0 xs But how does it work? Fold Basis case foldl (+) acc [] = acc Induction step Foldl (+) 0 (x1:xs) = (0 + x1) + fold (+) x1 (x2:xs') = (((0+ x1) +x2) + fold (+) (x1+x2) (x3:xs'')) ... ... = ((((0 +x1) + x2 ) +x3 ).. + xi ..) + xn) Some remarks ● Haskell do not coerce types, it means that expressions such as 3 + 2.14 are ill typed. ● The lists must contained elements of the same type, there is no such a thing like [12,”boom”]. ● Even though Lambda abstraction are very useful in some abstractions most of the time is a better idea to give a meaningfully name to a function. ● At the contrary of Python tuples and list are not interchangeable data structures. Curryfication Let f and g be functions of x then the composition of this two functions can be denoted as f º g(x) == f (g (x)) We can translate this functional denotation in haskell as follows f x = recip x g x = sqrt x (f . g) x == f ( g x) And what about this one? (5*). (rem 4) $ 3 Curryfication $ has the same meaning that a parenthesis then sqrt $ recip 3.0 == sqrt (recip 3.0) rem :: Int → Int → Int (*) :: Int → Int → Int Rem 4 :: Int → Int (5*) :: Int → Int rem 4 3 :: Int (5*1) :: Int (*5) . (rem 4) :: Int → Int (*5) . (rem 4) $ 2 :: Int Let set aside the pure ones from the impure The meaning of function in Haskell is the mathematical one, given the same input a function will always return the same output. But if all the expressions in Haskell are functions how could we interact with operations and effects with the real world? If a function lives in the pure world how can I inject the input in the functions? IO Monad to the Rescue!!!! IO Monad If the functions live in the pure world, we can bring them to a “secure zone” where we can “bind” a value to the function. We denote this zone where interaction with the external world is allowed the IO Monad. f :: [Double] → [Double] f xs = map ((^2). sin) xs main :: IO () main = let ys = f [pi,2.0*pi,-pi,0.5*pi] print ys Keep in your mind !! ● Before you type something you must have a plan. ● Haskell is not only a tool for structuring complex data and operations, it is also a path for acquiring abstraction skills. ● The Static type system protects you against meaningless expressions but could be a nightmare if you do not have the structure of the program in your head. Beware Fortranians !! Welcome to the Haskell Ab Initio Quantum Project Ĥaskell Ψ >>= λ → εΨ .