:reload
reload all names in scope
:quit
:t 9
returns the type of 9
:info []
returns lots of useful details about the implemented typeclasses
:k Int
returns the kind of Int
:set prompt "\x03BB > "
would change the command prompt to λ >
:set -XExistentialQuantification
sets up the language extension
You can give multiline input to GHCi as follows:
*Main> :{*Main| let askname = do*Main| putStrLn "What is your name?"*Main| name <- getLine*Main| putStrLn $ "Hello " ++ name*Main| :}*Main>
The best way to find out about these kind of constructs in ghci, e.g. :info <*>
:
(.)
- Function composition
<*>
$
Guard Syntax allows us to conditionally check a statement within a pattern matching expression.
describeLetter :: Char -> StringdescribeLetter c| c >= 'a' && c <= 'z' = "Lower case"| c >= 'A' && c <= 'Z' = "Upper case"| otherwise = "Not an ASCII letter"
Define inline bindings (e.g. to functions or values). The following example uses guards and a where clase:
bmiTell :: (RealFloat a) => a -> a -> StringbmiTell weight height| bmi <= 18.5 = "You're underweight, you emo, you!"| bmi <= 25.0 = "You're supposedly normal. Pffft, I bet you're ugly!"| bmi <= 30.0 = "You're fat! Lose some weight, fatty!"| otherwise = "You're a whale, congratulations!"where bmi = weight / height ^ 2
The 'as' pattern (described here, here and here), gives us a way of matching a name for the entire element being pattern matched in a list:
The following would be read all as (x:xs)
:
capital :: String -> Stringcapital "" = "Empty string, whoops!"capital all@(x:xs) = "The first letter of " ++ all ++ " is " ++ [x]
This page from 'Learn you a Haskell' is a good reference.
Import hiding
import Data.List hiding (nub)
From this page, the golden rule of indentation is:
Code which is part of some expression should be indented further in than the beginning of that expression...All grouped expressions must be exactly aligned
But you can avoid indentation:
Indentation is actually optional if you instead use semicolons and curly braces
In the following snippet (reference):
data
means we're declaring a new type
Expr
is the type constructor
I ...
, Add ...
, Mul ...
are the value constructors
data Expr = I Int -- integer constants| Add Expr Expr -- add two expressions| Mul Expr Expr -- multiply two expressions
Adding deriving (Show)
at the end of a data declaration automatically makes that type part of the Show typeclass (reference):
data Expr = I Int -- integer constants| Add Expr Expr -- add two expressions| Mul Expr Expr -- multiply two expressionsderiving (Show)
Syntactic sugar providing data accessors:
data Configuration = Configuration{ username :: String, localHost :: String, remoteHost :: String, isGuest :: Bool, isSuperuser :: Bool, currentDir :: String, homeDir :: String, timeConnected :: Integer}
You can pattern match against them:
getHostData (Configuration { localHost = lh, remoteHost = rh }) = (lh, rh)
And create new versions with certain fields overwritten using:
cfg { currentDir = newDir }
For the moment, I treat newtype
as being broadly interchangable with data
when creating a new type. There's documentation about it here.
A set with an associative binary operation. Superset of Monoids.
Monoid is a typeclass with an associative mappend
operation and an identity element.
Integer numbers form a monoid under addition with 0 as identity element Integer numbers form a monoid under multiplication with 1 as identity element Lists form a monoid under concatenation with the empty list as identity element
mappend
is given the infix synonym (<>)
The crux of GADTs is that the provide a way to explicitly declare the type signature of each constructor.
The following language option is required:
{-#LANGUAGE GADTs #-}
And then an example would be:
data Maybe a whereNothing :: Maybe aJust :: a -> Maybe a
Template Haskell is similar to Lisp macros.
{-# LANGUAGE TemplateHaskell #-}
It is used e.g. by lens
to generate the various lenses into data structures at compile time
forall
imposes constraints on parameterising types when defining new data types