cabal (sometimes cabal-install) + GHCCreate a file called hello.hs with the following contents:
main = putStrLn "Hello, world!"Compile your program to a native executable like this:
$ ghc --make hello
[1 of 1] Compiling Main ( hello.hs, hello.o )
Linking hello ...
$ ./hello
Hello, world!Or run it in the GHCI interpreter like this:
$ ghci hello.hs
GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help
...
Ok, modules loaded: Main.
*Main> main
Hello, world!
*Main> Haskell uses the = sign to declare bindings:
x = 2 -- Two hyphens introduce a comment
y = 3 -- ...that continues to end of line.
main = let z = x + y -- let introduces local bindings
in print z -- program will print 5
;", which is usually auto-inserted by a layout ruleadd arg1 arg2 = arg1 + arg2 -- defines function add
five = add 2 3 -- invokes function addParentheses can wrap compound expressions, must do so for arguments
bad = print add 2 3 -- error! (print should have only 1 argument)
main = print (add 2 3) -- ok, calls print with 1 argument, 5x = 5
x = 6 -- error, cannot re-bind x
safeDiv x y =
let q = div x y -- safe as q never evaluated if y == 0
in if y == 0 then 0 else q
main = print (safeDiv 1 0) -- prints 0
x = 5 -- this x is not used in main
main = let x = x + 1 -- introduces new x, defined in terms of itself
in print x -- program "diverges" (i.e., loops forever)In C, we use mutable variables to create loops:
long
factorial (int n)
{
long result = 1;
while (n > 1)
result *= n--;
return result;
}In Haskell, use recursion to "re-bind" argument symbols in new scope
factorial n = if n > 1
then n * factorial (n-1)
else 1
This Haskell code requires n stack frames
factorial n = if n > 1 then n * factorial (n-1) else 1factorial n multiplies by n after evaluating factorial (n-1)Idea: use accumulator argument to make calls tail recursive
factorial n = let loop acc n' = if n' > 1
then loop (acc * n') (n' - 1)
else acc
in loop 1 n
loop is tail recursive, compiles to an actual loopwhere clausesGuards let you shorten function declarations:
factorial n = let loop acc n' | n' > 1 = loop (acc * n') (n' - 1)
| otherwise = acc
in loop 1 n
|" symbol introduces a guardTrue guard winsotherwise = TrueBindings can also end with where clauses--like inverted let
factorial n = loop 1 n
where loop acc n' | n' > 1 = loop (acc * n') (n' - 1)
| otherwise = acc
let, a where clause scopes over multiple guarded definitionsloop) often have arguments related to outer function
' (prime) to the inner-function's argument' character in variables, except as first characterfactorial n = loop 1 n
where loop acc n' | n' > 1 = loop (acc * n) (n' - 1) -- bug
| otherwise = acc
factorial n0 = loop 1 n0
where loop acc n | n > 1 = loop (acc * n) (n - 1)
| otherwise = acc
factorial n0 = loop 1 n" causes compile errorBool - either True or FalseChar - a unicode code point (i.e., a character)Int - fixed-size integerInteger - an arbitrary-size integerDouble - an IEEE double-precision floating-point number-> type2 - a function from type1 to type2(type1, type2, ..., typeN) - a tuple() - a zero-tuple, pronounced unit (kind of like void in C); there is only one value of this type, also written ()You can declare the type of a symbol or expression with ::
x :: Integer
x = (1 :: Integer) + (1 :: Integer) :: Integer
:: has lower precedence than any function operators (including +)Function application happens one argument at a time (a.k.a. "currying")
add :: Integer -> (Integer -> Integer)
add arg1 arg2 = arg1 + arg2
add 2 3 is equivalent to (add 2) 3(add 2) takes 3 returns 5, so (add 2) has type Integer -> Integer-> associates to the right, so parens usually omitted in multi-argument function types:fn :: argType1 -> argType2 -> ... -> argTypeN -> resultType:t*Main> :t add
add :: Integer -> Integer -> Integer
The data keyword declares user-defined data types (like struct in C):
data PointT = PointC Double Double deriving Show
PointT with constructor PointC containing two Doublesderiving Show means you can print the type (helpful in GHCI)Read, Eq, Ord, Enum, BoundedTypes and constructors can use the same name (often do), E.g.:
data Point = Point Double Double deriving ShowOne type can have multiple constructors (like a tagged union):
data Point = Cartesian Double Double
| Polar Double Double
deriving Show
data Color = Red | Green | Blue | Violet deriving (Show, Eq, Enum)Constructors act like functions producing values of their types
data Point = Point Double Double deriving Show
myPoint :: Point
myPoint = Point 1.0 1.0
data Color = Red | Green | Blue | Violet deriving (Show, Eq, Enum)
myColor :: Color
myColor = Redcase statements & function bindings "de-construct" values with patterns
getX, getMaxCoord :: Point -> Double
getX point = case point of
Point x y -> x
getMaxCoord (Point x y) | x > y = x
| otherwise = y
isRed :: Color -> Bool
isRed Red = True -- Only matches constructor Red
isRed c = False -- Lower-case c just a variableGiven the following types for a rock-paper-scissors game:
data Move = Rock | Paper | Scissors
deriving (Eq, Read, Show, Enum, Bounded)
data Outcome = Lose | Tie | Win deriving (Show, Eq, Ord)outcome :: Move -> Move -> Outcome
GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help
...
*Main> outcome Rock Paper
Lose
*Main> outcome Scissors Paper
Win
*Main> outcome Paper Paper
Tie
data Move = Rock | Paper | Scissors deriving (Eq, Read, Show, Enum, Bounded)
data Outcome = Lose | Tie | Win deriving (Show, Eq, Ord)
-- | @outcome our_move their_move@
outcome :: Move -> Move -> Outcome
outcome Rock Scissors = Win
outcome Paper Rock = Win
outcome Scissors Paper = Win
outcome us them | us == them = Tie
| otherwise = Lose
data Maybe a = Just a
| Nothing
data Either a b = Left a
| Right bYou can see these at work in GHCI:
Prelude> :t Just True
Just True :: Maybe Bool
Prelude> :t Left True
Left True :: Either Bool b Left True contains a type variable, b
Left True can be of type Either Bool b for any type b_" can be bound but not used
isJust :: Maybe a -> Bool -- note parametric polymorphism
isJust (Just _) = True
isJust Nothing = False
isRed Red = True
isRed _ = False -- we don't need the non-red value
_ avoids thisYou can deconstruct types and bind variables within guards, E.g.:
addMaybes mx my | Just x <- mx, Just y <- my = Just (x + y)
addMaybes _ _ = Nothing
though often there is a simpler way
addMaybes (Just x) (Just y) = Just (x + y)
addMaybes _ _ = NothingWe could define homogeneous lists with the data keyword
data List a = Cons a (List a) | Nil
oneTwoThree = (Cons 1 (Cons 2 (Cons 3 Nil))) :: List IntegerList Integer, the type is written [Integer]Cons, the constructor is called : and is infixNil, the empty list is called []oneTwoThree = 1:2:3:[] :: [Integer]
oneTwoThree' = [1, 2, 3] -- comma-separated elements within brackets
oneTwoThree'' = [1..3] -- define list by a rangeString is just a list of Char, so ['a', 'b', 'c'] == "abc"You can pattern match on literal lists and Strings
head :: [a] -> a
head (x:_) = x
head [] = error "head: empty list"
tail :: [a] -> [a] -- all but first element
tail (_:xs) = xs
tail [] = error "tail: empty list"
a ++ b :: [a] -> [a] -> [a] -- infix operator concatenate lists
[] ++ ys = ys
(x:xs) ++ ys = x : xs ++ ys
length :: [a] -> Int -- This code is from language spec
length [] = 0 -- GHC implements differently, why?
length (_:l) = 1 + length l
filter :: (a -> Bool) -> [a] -> [a]
filter pred [] = []
filter pred (x:xs)
| pred x = x : filter pred xs
| otherwise = filter pred xs
Note function error :: String -> a reports assertion failures
deriving Read and readsderiving Show" and show to print values
show show gives you a valid Haskell expression*Main> show $ Point 1.0 1.0
"Point 1.0 1.0" <-- could paste string into your source"deriving Read" lets you parse a value at run time
data Point = Point Double Double deriving (Show, Read)
reads parses and returns [(value, string_with_rest_of_input)]*Main> reads "invalid Point 1 2" :: [(Point, String)]
[]
*Main> reads "Point 1 2" :: [(Point, String)]
[(Point 1.0 2.0,"")]
*Main> reads "Point 1 2 and some extra stuff" :: [(Point, String)]
[(Point 1.0 2.0," and some extra stuff")]
*Main> reads "(Point 1 2)" :: [(Point, String)] -- note parens OK
[(Point 1.0 2.0,"")]readsWrite a function to parse moves:
parseMove :: String -> Maybe Move
Just move on successful parse, Nothing otherwiseExamples of use:
*Main> parseMove "Rock"
Just Rock
*Main> parseMove "Paper"
Just Paper
*Main> parseMove "Scissors plus extra junk"
Nothing
Use reads:
parseMove :: String -> Maybe Move
parseMove str = case reads str of [(m, "")] -> Just m
_ -> Nothing
reads return type implicitly constrained by parseMove's type declaration
Removing parseMove's type would make calling it difficult
Directly match keywords:
parseMove :: String -> Maybe Move
parseMove "Rock" = Just Rock
parseMove "Paper" = Just Paper
parseMove "Scissors" = Just Scissors
parseMove _ = Nothing
Note how strings are constructors---you can pattern match on them
But this solution too finicky--won't except trailing carriage returns or spaces. If you did this change to using reads.
"\n" or "\r\n"parseMove :: String -> Maybe Move
parseMove str = case reads str of
[(m, rest)] | ok rest -> Just m
_ -> Nothing
where ok = all (`elem` " \r\n")
*Main> parseMove "Rock \r\n"
Just Rock
*Main> parseMove "Rock \r\njunk"
Nothinglength function?haskell.org" is too long for me--I change to "ho"# marks are for "unboxed types", which are faster but not asymptoticallylen is tail recursiveHere's a function to count lower-case letters in a String
import Data.Char -- brings function isLower into scope
countLowerCase :: String -> Int
countLowerCase str = length (filter isLower str)length, countLowerCase might run in constant space
Recall Haskell evaluates expressions lazily... Means in most contexts values are interchangeable with function pointers (a.k.a. thunks)
A String is a [Char], which is a type with two values, a head and tail
But until each of the head or tail is needed, it can be stored as a function pointer
So length will causes filter to produce Chars one at a time
length does not hold on to characters once counted; can be garbage-collected at will
Here's an even more concise definition
countLowerCase :: String -> Int
countLowerCase = length . filter isLowerThe "." operator provides function composition
(f . g) x = f (g x)
f . g" is an ASCII approximation of mathematical "f ∘ g"countLowerCase's argument had name strFunction composition can be used almost like Unix pipelines
process = countLowercase . toPigLatin . extractComments . unCompressExercise: Write the type of "." without typing :t (.) into ghci
\variable(s) -> body\" is an ASCII approximation of "λ", so pronounced "lambda"Example:
countLowercaseAndDigits :: String -> Int
countLowercaseAndDigits =
length . filter (\c -> isLower c || isDigit c)Lambda abstractions can deconstruct values with patterns, e.g.:
... (\(Right x) -> x) ...
+, *, /, ., ||, :_, and '
add 1 21 `add` 2!#$%&*+./<=>?@\^|-~ or constructors starting ":"
(+) 1 2(,), (,,), (,,,), (,,,,), etc.Infix functions can be partially applied in a parenthesized section
stripPunctuation :: String -> String
stripPunctuation = filter (`notElem` "!#$%&*+./<=>?@\\^|-~:")
-- Note above string the SECOND argument to notElem ^.., :, ::, =, \, |, <-, ->, @, ~, =>, --)infixl/infixr/infix for left/right/no associativityelse clauses, and let...in clauses extend as far to the right as possible (meaning they never stop at any infix operator, no matter how low precedence)infixl 9 !! -- This is the default when fixity unspecified
infixr 9 .
infixr 8 ^, ^^, ⋆⋆
infixl 7 ⋆, /, `quot`, `rem`, `div`, `mod`
infixl 6 +, - -- Unary negation "-" has this fixity, too
infixr 5 ++ -- built-in ":" constructor has this fixity, too
infix 4 ==, /=, <, <=, >=, >, `elem`, `notElem`
infixr 3 &&
infixr 2 ||
infixl 1 >>, >>=
infixr 1 =<<
infixr 0 $, $!, `seq`
If you can't remember, use :i in GHCI:
Prelude> :i &&
(&&) :: Bool -> Bool -> Bool -- Defined in GHC.Classes
infixr 3 &&
infixl 9infixr 0" operators$ is function application, but with lowest precedence
($) :: (a -> b) -> a -> b
f $ x = f x
putStrLn $ "the value of " ++ key ++ " is " ++ show valueseq :: a -> b -> b just returns value of second argument...main = let q = 1 `div` 0
in seq q $ putStrLn "Hello world!\n" -- exception
seq has to be built into the compiler$! combines $ and seq
f $! x = x `seq` f xn0 stack frames in factorial:factorial n0 = loop 1 n0
where loop acc n | n > 1 = loop (acc * n) (n - 1)
| otherwise = acc
acc can contain a chain of thunks n long(((1 * n) * (n - 1)) * (n - 2) ...) -- Laziness means only evaluated when needed$! or seqfactorial n0 = loop 1 n0
where loop acc n | n > 1 = (loop $! acc * n) (n - 1)
| otherwise = acc
factorial n0 = loop 1 n0
where loop acc n | n > 1 = acc `seq` loop (acc * n) (n - 1)
| otherwise = acc
cabal update to create $HOME/.cabal, download package databaseI highly recommend unconmenting and editing these two lines in $HOME/.cabal/config
documentation: True
library-profiling: True$HOME/.cabal/bin to your pathI use the following shell alias
alias cbi='LC_CTYPE=en_US.UTF-8 cabal install --user --haddock-hyperlink-source'E.g., run: cbi network
$HOME/.cabal, and records them in $HOME/.ghc$HOME/.cabal and $HOME/.ghcimport syntaxMain, as programs start at function main in MainMain, a module named M must reside in a file named M.hsMain modulesLet's add this to the top of our source file
module Main where -- redundant since Main is the default
import System.IO
module name where" or "module name (exported-symbol[, ...]) where" (non-exported symbols provide modularity)import module - imports all symbols in moduleimport qualified module as ID - prefixes imported symbols with ID.import module (function1[, function2 ...]) - imports just the named functionsimport module hiding (function1[, function2 ...]) - imports all but the named functionsdo notationLet's write a function to greet someone
Type the following into a file greet.hs:
wget cs240h.stanford.edu/greet1.hsmodule Main where
import System.IO
greet h = do
hPutStrLn h "What is your name?"
name <- hGetLine h
hPutStrLn h $ "Hi, " ++ name
withTty = withFile "/dev/tty" ReadWriteMode
main = withTty greet
main in GHCIdo notationgreet h = do
hPutStrLn h "What is your name?"
name <- hGetLine h
hPutStrLn h $ "Hi, " ++ name
do block lets you sequence IO actions. In a do block:
<- action - binds pat (variable or constructor pattern) to result of executing actionlet pat = pure-value - binds pat to pure-value (no "in ..." required)do block (i.e., can use <-, need let for bindings)do/let/case won't parse after prefix function
func $ do ..."func (do ...)"main :: IO ()
greet :: Handle -> IO ()
hPutStrLn :: Handle -> String -> IO ()
hGetLine :: Handle -> IO String
IO is a parameterized type (just as Maybe is parameterized)
IO String" means IO action that produces a String if executedMaybe, we won't use a constructor for IO, which is somewhat magicWhat if we try to copy a line of input as follows?
main = hPutStrLn stdout (hGetLine stdin)
hPutStrLn expects type String, while hGetLine returns an IO StringIO [String] to get a [String]
case, because we don't have a constructor for IO... Besides, the order and number of deconstructions of something like hPutStr matters<- operator in do blocks!do name <- hGetLine h
hPutStrLn h $ "Hi, " ++ name
hGetLine and hPutStrLn return IO actions that can change the world
main action is ever executeddo name <- hGetLine h
hPutStrLn h $ "Hi, " ++ name
do block builds a compound action from other actions
IO a actions to the world, extracting values of type aagreet$ ghc --make greet
[1 of 1] Compiling Main ( greet.hs, greet.o )
Linking greet ...
$ ./greet
What is your name?
David
Hi, David
What if you want to run it in GHCI?
$ ghci ./greet.hs
...
Prelude Main>
* before Main means no access to internal symbols (because compiled), need to say:Prelude Main> :load *greet.hs
[1 of 1] Compiling Main ( greet.hs, interpreted )
Ok, modules loaded: Main.
*Main> return functiongreet to return the name of the person?
hPutStrLn :: IO (); want to end with action returning nameThis does not work:
do ...
hPutStrLn h $ "Hi, " ++ name
name -- Incorrect, will not compileProblem: every action in an IO do block must have type IO a for some a
Solution: return function gives trivial IO action returning a particular value
greet :: Handle -> IO String
greet h = do
hPutStrLn h "What is your name?"
name <- hGetLine h
hPutStrLn h $ "Hi, " ++ name
return nameNote: return is not control flow statement, just a function
return :: a -> IO a." (fixity infixr 9)Function >>= (pronounced "bind") allows point-free IO composition
(>>=) :: IO a -> (a -> IO b) -> IO b
infixl 1 >>=Let's re-write greet with point-free style to avoid variable name
greet h = do
hPutStrLn h "What is your name?"
hGetLine h >>= hPutStrLn h . ("Hi, " ++)
>>= composes left-to-right, while . goes right-to-leftdo blocks are just syntactic sugar for calling >>=
-- Desugared version of original greet:
greet h = hPutStrLn h "What is your name?" >>= \_ ->
hGetLine h >>= \name ->
hPutStrLn h ("Hi, " ++ name)Handle, tell user whether s/he won/lost/tiedcomputerVsUser :: Move -> Handle -> IO ()Starter code: wget cs240h.stanford.edu/rock1.hs
Example:
*Main> withTty $ computerVsUser Rock
Please enter one of [Rock,Paper,Scissors]
garbage
Please enter one of [Rock,Paper,Scissors]
Paper
You Win
*Main> withTty $ computerVsUser Scissors
Please enter one of [Rock,Paper,Scissors]
Paper
You LosegetMove :: Handle -> IO Move
getMove h = do
hPutStrLn h $ "Please enter one of " ++ show ([minBound..] :: [Move])
-- Here is the added code:
input <- hGetLine h
case parseMove input of Just move -> return move
Nothing -> getMove h
computerVsUser :: Move -> Handle -> IO ()
computerVsUser computerMove h = do
userMove <- getMove h
let o = outcome userMove computerMove
hPutStrLn h $ "You " ++ show o
id :: a -> a
id x = x
const :: a -> b -> a
const a _ = a
fst :: (a, b) -> a
fst (a, _) = a
snd :: (a, b) -> b
snd (_, b) = b
print a = putStrLn (show a) -- what's the type? a -> IO ()?
show a = ??? -- how to implement?
id :: a -> a just passes the value through1 + 1 and 1.0 + 1.0 compute very different functionsshow converts value to String, depends entirely on input typederiving Show" in declarations)show a function (type Int -> Int)Ad-hoc polymorphic functions are called methods and declared with classes
class MyShow a where
myShow :: a -> StringThe actual method for each type is defined in an instance declaration
data Point = Point Double Double
instance MyShow Point where
myShow (Point x y) = "(" ++ show x ++ ", " ++ show y ++ ")"
What's the type of a function that calls myShow? Ask GHCI:
myPrint x = putStrLn $ myShow x
*Main> :t myPrint
myPrint :: MyShow a => a -> IO ()(class type-var, ...) =>" at start of type, E.g.:myPrint :: MyShow a => a -> IO ()
sortAndShow :: (Ord a, MyShow a) => [a] -> String
elem :: (Eq a) => a -> [a] -> Bool
elem _ [] = False
elem x (y:ys) = x==y || elem x ys
add :: (Num a) => a -> a -> a
add arg1 arg2 = arg1 + arg2myPrint, you explicitly give it a value of type aa's MyShow instanceLet's say you want to cache result of super-expensive function
superExpensive val = len $ veryExpensive (val :: Int)
where len [] = 0
len (x:xs) = 1 + len xs
cachedResult = superExpensive 5
cachedResult will start as thunk, be executed once, then contain valueLet's think about the types
*Main> :t superExpensive
superExpensive :: Num a => Int -> a
*Main> :t cachedResult
cachedResult :: Integer
superExpensive can return any Num you wantcachedResult :: (Num a) => a?cachedResult into a function, undermining our caching goal!f), rather than a pattern ((x, y) = ..., (Just x) = ...)f x = ... ok, f = ... not)Num, try Integer then Double (this sequence can be changed with a default declaration)This code will compile
-- Compiler infers: show1 :: (Show x) => x -> String
show1 x = show xBut neither of these will:
show2 = show
show3 = \x -> show x
Add type signatures to functions--a good idea anyway for top-level bindings, and sometimes necessary for let bindings
-- No problem, compiler knows you want ad hoc polymorphism
show2 :: (Show x) => x -> String
show2 = showEq contains '==' and '/=' methods, while Ord contains <, >=, >, <=, etc.Ord instance not also be an Eq instanceOrd declares Eq as a superclass, using a context
class Eq a => Ord a where
(<), (>=), (>), (<=) :: a -> a -> Bool
a <= b = a == b || a < b -- default methods can use superclasses
....Ord dictionary can lookup the Eq dictionarymyShow for a list of items whose type is of class MyShowinstance (MyShow a) => MyShow [a] where
myShow [] = "[]"
myShow (x:xs) = myShow x ++ ":" ++ myShow xsFunctor is a class for parameterized types onto which you can map functions:
class Functor f where
fmap :: (a -> b) -> f a -> f b
f, rather types f a and f bAn example of a Functor is Maybe:
instance Functor Maybe where
fmap _ Nothing = Nothing
fmap f (Just a) = Just (f a)
GHCi, version 7.6.3: http://www.haskell.org/ghc/ :? for help
Prelude> fmap (+ 1) Nothing
Nothing
Prelude> fmap (+ 1) $ Just 2
Just 3FunctorsLists are a Functor
[] can be used as a prefix type constructor ("[] Int" means "[Int]") and can be used to declare instancesmap :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
instance Functor [] where
fmap = mapIO is a Functor
instance Functor IO where
fmap f io = io >>= return . f
-- equivalent to: do val <- io; return (f val)
greet h = do
hPutStrLn h "What is your name?"
fmap ("Hi, " ++) (hGetLine h) >>= hPutStrLn hWhat happens if you try to make an instance of Functor for Int?
instance Functor Int where -- compilation error
fmap _ _ = error "placeholder"
fmap :: (a -> b) -> Int a -> Int b, but Int not parameterizedInt, Double, ()) directly describes valuesMaybe, [], IO)Either, (,))Int, Double, (), etc.)Maybe, IO, etc.)Either)Monad classreturn and >>= are actually methods of a class called Monadclass Monad m where
(>>=) :: m a -> (a -> m b) -> m b
return :: a -> m a
fail :: String -> m a -- called when pattern binding fails
fail s = error s -- default is to throw exception
(>>) :: m a -> m b -> m b
m >> k = m >>= \_ -> k
do blocks for non-IO purposesMonad--invent a new monad, and you can still use much existing codeMaybe monadSystem libraries define a Monad instance for Maybe
instance Monad Maybe where
(Just x) >>= k = k x
Nothing >>= _ = Nothing
return = Just
fail _ = NothingNothing to indicate failure
extractA :: String -> Maybe Int
extractB :: String -> Maybe String
...
parseForm :: String -> Maybe Form
parseForm raw = do
a <- extractA raw
b <- extractB raw
...
return (Form a b ...)
IO threaded WorldNothingSome data types have a large number of fields
-- Argument to createProcess function
data CreateProcess = CreateProcess CmdSpec (Maybe FilePath)
(Maybe [(String,String)]) StdStream StdStream StdStream Bool
Algebraic data types let you label fields (like C structs)
data CreateProcess = CreateProcess {
cmdspec :: CmdSpec,
cwd :: Maybe FilePath,
env :: Maybe [(String,String)],
std_in :: StdStream,
std_out :: StdStream,
std_err :: StdStream,
close_fds :: Bool
}Let's make an algebraic version of our Point class
data Point = Point { xCoord :: Double, yCoord :: Double }data Point = Point { xCoord :: Double, yCoord :: Double }
Can initialize an Algebraic type by naming fields
myPoint = Point { xCoord = 1.0, yCoord = 1.0 }
undefined - a thunk that throws an exceptionCan also pattern-match on any subset of fields
-- Note the pattern binding assigns the variable on the right of =
getX Point{ xCoord = x } = x
As-patterns are handy to bind a variable and pattern simultaneously (with @):
getX' p@Point{ xCoord = x }
| x < 100 = x
| otherwise = error $ show p ++ " out of range"
-- Also works with non-algebraic patterns
getX' p@(Point x _) = ...
processString s@('$':_) = ...
processString s = ...Can use field labels as access functions
getX point = xCoord point
xCoord works anywhere you can use a function of type Point -> DoubleThere is a special syntax for updating one or more fields
setX point x = point { xCoord = x }
setXY point x y = point { xCoord = x, yCoord = y }
Obviously doesn't update destructively, but returns new, modified Point
Very handy to maintain state in tail recursive functions and Monads
A ! before a data field type makes it strict - i.e., can't be thunk
data State = State !Int Int
data AlgState = AlgState { accumulator :: !Int
, otherValue :: Int }
In both cases above, the first Int cannot hold a thunk, but only a value
When initializing an algebraic datatype, it is mandatory to initialize all strict fields (since they cannot hold the undefined thunk).
High-level Stream (TCP & Unix-domain) socket support in Network
connectTo :: HostName -> PortID -> IO Handle
listenOn :: PortID -> IO Socket
accept :: Socket -> (Handle, HostName, PortNumber)
sClose :: Socket -> IO ()Low-level BSD socket functions in Network.Socket
socket :: Family -> SocketType -> ProtocolNumber -> IO Socket
connect :: Socket -> SockAddr -> IO ()
bindSocket :: Socket -> SockAddr -> IO ()
listen :: Socket -> Int -> IO ()
accept :: Socket -> IO (Socket, SockAddr) -- not same accept as above
getAddrInfo looks up hostnames just like [RFC3493] (returns [AddrInfo])
We'll stick to the higher-level functions today
Instead of withTty, let's define withClient that uses TCP:
wget cs240h.stanford.edu/rock2.hswithClient :: PortID -> (Handle -> IO a) -> IO a
withClient listenPort fn = do
s <- listenOn listenPort
(h, host, port) <- accept s
putStrLn $ "Connection from host " ++ host ++ " port " ++ show port
sClose s -- Only accept one client
a <- fn h
hClose h
return aTry it like this:
*Main> withClient (PortNumber 1617) (computerVsUser Rock)
$ nc localhost 1617
Please enter one of [Rock,Paper,Scissors]
Rock
You Tie