ThoughtWorks




               Haskell Jumpstart
                    David Vollbracht
For this special net presentation the
 part of David Vollbracht will be played
by OS X’s “Kathy” text to speech voice
Agenda
Basic Syntax
Tools to Write This Program
(Almost) Nothing Else
in g
     r n
Wa
     This Intro is Deliberately
            Incomplete
For More Info:
learnyouahaskell.com
Compiler & REPL
GHC
The Glasgow Haskell Compiler
GHCi
Interactive Prompt to Evaluate Expressions
port install ghc
apt-get update && apt-get install ghc6 ghc6-prof ghc6-doc
                    yum install ghc
           ...
Basic Syntax
Whitespace Denotes
Function Application
f a b
Function f




             f a b
f a b
Parameter 1
f a b
    Parameter 2
Group Expressions with
       Parens
f (a b)
Function f




      f (a b)
Parameter to f




f (a b)
f (a b)
 Function a
f (a b)
    Parameter to a
g e t
         F o r
 o n’t
D
     Parens change precedence.
      They don’t call functions.
Conditionals:
 If and Case
if a then b else c
Boolean Expression




  if a then b else c
if a then b else c

Expression when a is true
if a then b else c


       Expression when a is false
g e t
         F o r
 o n’t
D
          If ALWAYS has an else.
case a of
b -> x
c -> y
otherwise -> z
Branch expression


case a of
b -> x
c -> y
otherwise -> z
Cases
        case a of
        b -> x
        c -> y
        otherwise -> z
case a of
          Result expressions
b -> x
c -> y
otherwise -> z
case a of
b -> x
c -> y
otherwise -> z
case a of
      b -> x
      c -> y
      otherwise -> z
Default Case
Let Binding
let a = f b
in g a
Binding




let a = f b
in g a
Expression




let a = f b
in g a
let a = f b
   in g a

Expression involving binding
g e t
         F o r
 o n’t
D
                  Bindings are NOT
                      variables.
Multiline Expressions
let a = f b
     c
    d = g e
in g a
let a = f b
     c   Indent after let or of
    d = g e
in g a
let a = f b c

    d = g e
in g a
No indentation needed
when not using ‘let’ or
      ‘case x of’
      (or ‘do’ or ‘where’)
Please indent responsibly
let k = f b
          c
    j = k d
          e
              case a of
in h k j
              b -> f a
                  ...
Functions
In GHCI, use let
let f a b = <expr>
Function f




let f a b = <expr>
let f a b = <expr>

 Parameter 1
let f a b = <expr>

         Parameter 2
In source file, just define
       at top level
f a b = <expr>
Lists
Ordered Collection
Only One Type of Element
     Variable Length
[a, b, c]
List Constructor




[a, b, c]
[a, b, c]
Element 0   Element 1   Element 2
Type Signatures
"Hello"   :: [Char]
Separates expression from type




"Hello"        :: [Char]
f :: Char -> [Char]
f x = [x, x]
f :: Char -> [Char]
f x = [x, x]


  Function Definition
Type Signature




f :: Char -> [Char]
f x = [x, x]
Polymorphic Functions
         &
 Parameterized Types
head “abc” :: ?
head “abc” :: Char
head :: ?
head :: [a] -> a
head :: [a] -> a
           Type Variable
head :: [a] -> a


      Parameterized Type
head :: [a] -> a
       Polymorphic Function
(Operates on many different types)
head takes a list of some type ‘a’ and
  gives you back one item of type ‘a’



head :: [a] -> a
Pattern Matching
let (x:xs) = [1, 2 ,3]
Pattern Match




let (x:xs) = [1, 2 ,3]
let (x:xs) = [1, 2 ,3]

     1
let (x:xs) = [1, 2 ,3]

       [2, 3]
let (x:xs) = [1, 2 ,3]
f (x:xs) = x * 2 : f xs
Pattern Match




f (x:xs) = x * 2 : f xs
f [] = []
Pattern Match




f [] = []
f [] = []
f (x:xs) = x * 2 : f xs
Matches happen in order of definition


 f [] = []
 f (x:xs) = x * 2 : f xs
Purity & Laziness
Functions Are “Pure”
They Always Produce the Same Result for the Same Value
Good For Reasoning
Good For Compiler Optimizations
Good For Parallel / Concurrent
       Programming
Haskell is Lazy
Because Functions Are Pure,
 Their Evaluation Can Wait
Impure Operations
getLine :: ?
Returns a single line from stdin




   getLine :: ?
getLine ::   String
getLine :: IO String
Means “I’m hiding a side effect”




getLine :: IO String
What can we do with an ‘IO String’?
Get at the String with do notation
main :: do
 s <- getLine
 putStrLn s
Ties together multiple functions that return IO a




main :: do
 s <- getLine
 putStrLn s
main :: do
              s <- getLine
 Unpacks IO putStrLn s
to get at the
underlying
  value
putStrLn :: ?
putStrLn :: String -> IO ()
Void Type



putStrLn :: String -> IO ()
Special Syntax Considerations
g e t
            F o r
    o n’t
D
            When Using do Notation
              let doesn’t use in
main :: do
 let s = "Hello"
 putStrLn s
g e t
       F o r
    o n’t Newline implies a new
D      statement in do notation.

        You must indent if more
     ...
main = do
 s <- getLine
 if s == "Hello"
  then return "Hi"
  else return "Bye"
Putting it All Together
Some Utility Functions
words ::    String ->
           [String]
Split on whitespace



 words ::              String ->
                      [String]
unwords :: [String] ->
            String
Joins with spaces



unwords :: [String] ->
            String
lines ::    String ->
            [String]

unlines :: [String] ->
            String
getContents :: IO String
Lazily reads all of stdin as a single string



getContents :: IO String
More haskell at
learnyouahaskell.com
Haskell Jumpstart
Haskell Jumpstart
Haskell Jumpstart
Haskell Jumpstart
Haskell Jumpstart
Haskell Jumpstart
Haskell Jumpstart
Haskell Jumpstart
Upcoming SlideShare
Loading in …5
×

Haskell Jumpstart

1,349 views

Published on

A minimal fluff introduction to Haskell showing enough tools to build a command line application to singularize every word in multiple lines. First presented at the first meeting of the Atlanta Functional Programming Users Group

Published in: Technology, Education
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
1,349
On SlideShare
0
From Embeds
0
Number of Embeds
4
Actions
Shares
0
Downloads
44
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide













  • GHCI is the repl that comes with GHC.
    Once GHC is installed, invoke it with by typing GHCI at the command line.
    You should set a prompt denoted by Prelude
    At the prompt we can evaluate any Haskell expression
    For instance, we can do simple mathematical operations
    We can also demonstrate Haskell&apos;s string syntax
    Or actually print a string to standardout
    To see the myriad of commands available in GHCI, type colon h
    To quit GHCI, type colon q at the prompt
    To compile a haskell program from a file, create a dot hs file with the program name you want.
    Declare a haskell module of the name Main and define the main function with in.
    When you compile your program, GHC will look in the Main module for the main function.
    When it is run, your program will start in the main function.
    Use the --make option to GHC to compile your program into an executable.
    GHC will create an executable file with the same name as the source file, but
    with no extension. Execute this file to see your program simply execute it

























  • It should not be surprising that functions play a central role in functional programming.
    Let&apos;s define some.

    In GHCI, we must use the let syntax to define a function
    Start with the let keyword, followed by the function name
    next list the parameter names, followed by spaces
    then an equals sign an another space
    and on the right side write the expression that defines the value of the function.
    We can use the function simply by typing it&apos;s name followed by any parameters

    Inside a haskell source file we can define top level functions simply using the equals syntax.
    There is no need to scope the definition inside of a let expression.

    You can try out functions from source file in GHCI using the load command.
    Type the name of the module you would like to load and GHCI will make its functions available to you



  • One of the most important data structures in Haskell is the list.
    Lists are written as comma delimited elements enclosed in square braces.
    The indexing operator can be used to look up elements in a list
    The head function accepts a list and returns its first element
    The tail function accepts a list and returns a new list without the head
    The length function accepts a list and returns its length
    The plus plus function concatenates two lists
    The colon function adds an item to the front of a list

    Strings are lists too. Lists of characters.
    So we can use head to get the first character of a string
    we can use tail to strip off the first character of a string
    and length to get the length of a string
    of course, the other list functions work on strings too

    There are lots and lots of list functions available in GHC.
    Consult the API docs to find out more about the options available



  • GHCI can help us investigate the haskell type of an expression

    Using the T command Followed by a haskell expression will show the type of that expression

    Functions are expressions too, so we can find out their type
    the T command followed by the function name will show you its type

    The arrow separates the types in the function signature.
    The last type is the return type, the rest are parameter type.
    This function accepts two Bools and returns a String, AKA list of Char
    There is a very good reason why the parameter and return types are both separated by arrows,
    but we won&apos;t go into that now.&quot;














  • There&apos;s a lot more that you can do with pattern matching other than deal with tuples.
    You can pattern match lists constructed with collun.
    Start with the Name to bind the first list element to
    follow it with the collun list constructer
    and then the Name to bind the rest of the list to.
    Now we can put a list value in.
    and see what values were bound
    The first value in the list, one, was bound to &apos;x&apos;. The
    rest of the list was bound to &apos;xs&apos;&quot;

    This pattern match reverses the operation of the colon function,
    which we can use to build the list back up
    You can use pattern matching define multiple branches of a function.
    Ignore the curly braces and semi-colluns. They&apos;re here to make GHCI happy.
    First we can define than &apos;f&apos; of the empty list is simply the empty list.
    This is our termination condition for a recursiv definition.
    With the empty case taken care of, we can safely pattern match a non-empty
    list and compute on it.
    Now we have a fuction that multiplies every item in a list by 2

    If we define a function that ends up failing to match a pattern,
    we will get an error message at runtime.







  • Because haskell is lazy, we can define an infinitely recursiv function.
    Let&apos;s define a function that starting at &apos;n&apos; and counts up by step &apos;s&apos;, returning a List.
    The first element of the list is simply &apos;n&apos;
    The remainder of the list is defined by recursivly calling &apos;f&apos;, using the next number in the list
    as the new starting point
    In a strict language we would recurs infinitely as soon as we used the &apos;f&apos; function.
    In Haskell, however, as long as we only ask for a finite portion of the list we are ok
    If we try to print out the entire list, then our program goes into a infinite loop.
    It will keep printing values forever, until we interrupt it with &apos;control c&apos;.




















  • To make this program work we&apos;ll need four pure functions and a main function
    Functions: singularize, singularizeWords, singularizeLines, singularizeContent
    Let&apos;s start with the &apos;singularize&apos; function. It&amp;#x2019;s type is String -&gt; String
    The singuralization scheme is going to be very naive: it will simply strip of a single trailing &apos;s&apos; character
    We&apos;ll implement the function with recursion, starting with the base case. **Problem is recursive**
    Using pattern matching on base case: handle when the recursion has no more characters left
    In this case, we are done so we will simply return an empty list.
    Let&apos;s start on the second case for the &apos;singuralize&apos; function. - will remove the &amp;#x2018;s&amp;#x2019; character
    When we encounter a list which is just an &apos;s&apos;, we want to handle it specially. Pattern = [&amp;#x2018;s&amp;#x2019;]. Return []
    The final branch of the function will handle the recursion. We&apos;ll Use pattern matching again to pull
    off the first character from the list. The pattern match is (x:xs)
    We&apos;ll also use the colon function to build the result. We&apos;ll simply start with the character matched by &apos;c&apos;,
    since we don&apos;t need to do any operations on it.
    Next is the collun function, which will be followed by the rest of the word being singularized.
    We complete our singuralization by recursing back using the remainder of the word.
    The &apos;singularizeWords&apos; function will use recursion to singularize each word in a list
    Again, we have the base case of an empty list, which we implement using pattern matching.
    And we implement the recursion using pattern matching to extract the first word from the list.
    We will singuralize a single word at a time and using recursion to singularize the rest of the list.
    The &apos;singularizeLines&apos; function will break each line in a list into words and singuralize them.
    Again, we use pattern matching for the base case of the recursion.
    And to extract the first line from the list from the rest of the list.
    In this case, we use the &apos;words&apos; function to break the line into words,
    which we then singularize. Then we join the result back together with &apos;unwords&apos;.
    The collun function will build a new list start with this line of singuralized words.
    And the rest of the list is build using recursion again.
    the &apos;singularizeContent&apos; function will break content into lines to be singuralized
    in this case we don&apos;t need to do any pattern matching because we don&apos;t need recursion.&quot;
    We simply use &apos;lines&apos; to break up the content, use the &apos;singuralizeLines&apos; function to process them, and &apos;unlines&apos; to join them back together.
    Finally we get to the &apos;main&apos; function. Until now every function in our application has been pure. We need a
    little bit of impurity to link it all together. We need to read the content from standard-in,
    process it, and print it back out.
    We&apos;ll use &apos;getContents&apos; to lazily read all the content from standard-in. The contents gets unpacked from the IO type into our binding, &apos;s&apos;, as a String.
    We&apos;ll use the &apos;singularizeContent&apos; content function to process the contentbeing read from standard-in. And finally we use &apos;print string line&apos; to print it out.

  • Haskell Jumpstart

    1. 1. ThoughtWorks Haskell Jumpstart David Vollbracht
    2. 2. For this special net presentation the part of David Vollbracht will be played by OS X’s “Kathy” text to speech voice
    3. 3. Agenda
    4. 4. Basic Syntax
    5. 5. Tools to Write This Program
    6. 6. (Almost) Nothing Else
    7. 7. in g r n Wa This Intro is Deliberately Incomplete
    8. 8. For More Info: learnyouahaskell.com
    9. 9. Compiler & REPL
    10. 10. GHC The Glasgow Haskell Compiler
    11. 11. GHCi Interactive Prompt to Evaluate Expressions
    12. 12. port install ghc apt-get update && apt-get install ghc6 ghc6-prof ghc6-doc yum install ghc pkg_add -r ghc emerge dev-lang/ghc cd /usr/ports/lang/ghc && make install
    13. 13. Basic Syntax
    14. 14. Whitespace Denotes Function Application
    15. 15. f a b
    16. 16. Function f f a b
    17. 17. f a b Parameter 1
    18. 18. f a b Parameter 2
    19. 19. Group Expressions with Parens
    20. 20. f (a b)
    21. 21. Function f f (a b)
    22. 22. Parameter to f f (a b)
    23. 23. f (a b) Function a
    24. 24. f (a b) Parameter to a
    25. 25. g e t F o r o n’t D Parens change precedence. They don’t call functions.
    26. 26. Conditionals: If and Case
    27. 27. if a then b else c
    28. 28. Boolean Expression if a then b else c
    29. 29. if a then b else c Expression when a is true
    30. 30. if a then b else c Expression when a is false
    31. 31. g e t F o r o n’t D If ALWAYS has an else.
    32. 32. case a of b -> x c -> y otherwise -> z
    33. 33. Branch expression case a of b -> x c -> y otherwise -> z
    34. 34. Cases case a of b -> x c -> y otherwise -> z
    35. 35. case a of Result expressions b -> x c -> y otherwise -> z
    36. 36. case a of b -> x c -> y otherwise -> z
    37. 37. case a of b -> x c -> y otherwise -> z Default Case
    38. 38. Let Binding
    39. 39. let a = f b in g a
    40. 40. Binding let a = f b in g a
    41. 41. Expression let a = f b in g a
    42. 42. let a = f b in g a Expression involving binding
    43. 43. g e t F o r o n’t D Bindings are NOT variables.
    44. 44. Multiline Expressions
    45. 45. let a = f b c d = g e in g a
    46. 46. let a = f b c Indent after let or of d = g e in g a
    47. 47. let a = f b c d = g e in g a
    48. 48. No indentation needed when not using ‘let’ or ‘case x of’ (or ‘do’ or ‘where’)
    49. 49. Please indent responsibly
    50. 50. let k = f b c j = k d e case a of in h k j b -> f a b c -> g a c
    51. 51. Functions
    52. 52. In GHCI, use let
    53. 53. let f a b = <expr>
    54. 54. Function f let f a b = <expr>
    55. 55. let f a b = <expr> Parameter 1
    56. 56. let f a b = <expr> Parameter 2
    57. 57. In source file, just define at top level
    58. 58. f a b = <expr>
    59. 59. Lists
    60. 60. Ordered Collection Only One Type of Element Variable Length
    61. 61. [a, b, c]
    62. 62. List Constructor [a, b, c]
    63. 63. [a, b, c] Element 0 Element 1 Element 2
    64. 64. Type Signatures
    65. 65. "Hello" :: [Char]
    66. 66. Separates expression from type "Hello" :: [Char]
    67. 67. f :: Char -> [Char] f x = [x, x]
    68. 68. f :: Char -> [Char] f x = [x, x] Function Definition
    69. 69. Type Signature f :: Char -> [Char] f x = [x, x]
    70. 70. Polymorphic Functions & Parameterized Types
    71. 71. head “abc” :: ?
    72. 72. head “abc” :: Char
    73. 73. head :: ?
    74. 74. head :: [a] -> a
    75. 75. head :: [a] -> a Type Variable
    76. 76. head :: [a] -> a Parameterized Type
    77. 77. head :: [a] -> a Polymorphic Function (Operates on many different types)
    78. 78. head takes a list of some type ‘a’ and gives you back one item of type ‘a’ head :: [a] -> a
    79. 79. Pattern Matching
    80. 80. let (x:xs) = [1, 2 ,3]
    81. 81. Pattern Match let (x:xs) = [1, 2 ,3]
    82. 82. let (x:xs) = [1, 2 ,3] 1
    83. 83. let (x:xs) = [1, 2 ,3] [2, 3]
    84. 84. let (x:xs) = [1, 2 ,3]
    85. 85. f (x:xs) = x * 2 : f xs
    86. 86. Pattern Match f (x:xs) = x * 2 : f xs
    87. 87. f [] = []
    88. 88. Pattern Match f [] = []
    89. 89. f [] = [] f (x:xs) = x * 2 : f xs
    90. 90. Matches happen in order of definition f [] = [] f (x:xs) = x * 2 : f xs
    91. 91. Purity & Laziness
    92. 92. Functions Are “Pure” They Always Produce the Same Result for the Same Value
    93. 93. Good For Reasoning
    94. 94. Good For Compiler Optimizations
    95. 95. Good For Parallel / Concurrent Programming
    96. 96. Haskell is Lazy
    97. 97. Because Functions Are Pure, Their Evaluation Can Wait
    98. 98. Impure Operations
    99. 99. getLine :: ?
    100. 100. Returns a single line from stdin getLine :: ?
    101. 101. getLine :: String
    102. 102. getLine :: IO String
    103. 103. Means “I’m hiding a side effect” getLine :: IO String
    104. 104. What can we do with an ‘IO String’? Get at the String with do notation
    105. 105. main :: do s <- getLine putStrLn s
    106. 106. Ties together multiple functions that return IO a main :: do s <- getLine putStrLn s
    107. 107. main :: do s <- getLine Unpacks IO putStrLn s to get at the underlying value
    108. 108. putStrLn :: ?
    109. 109. putStrLn :: String -> IO ()
    110. 110. Void Type putStrLn :: String -> IO ()
    111. 111. Special Syntax Considerations
    112. 112. g e t F o r o n’t D When Using do Notation let doesn’t use in
    113. 113. main :: do let s = "Hello" putStrLn s
    114. 114. g e t F o r o n’t Newline implies a new D statement in do notation. You must indent if more than usual
    115. 115. main = do s <- getLine if s == "Hello" then return "Hi" else return "Bye"
    116. 116. Putting it All Together
    117. 117. Some Utility Functions
    118. 118. words :: String -> [String]
    119. 119. Split on whitespace words :: String -> [String]
    120. 120. unwords :: [String] -> String
    121. 121. Joins with spaces unwords :: [String] -> String
    122. 122. lines :: String -> [String] unlines :: [String] -> String
    123. 123. getContents :: IO String
    124. 124. Lazily reads all of stdin as a single string getContents :: IO String
    125. 125. More haskell at learnyouahaskell.com

    ×