Skip to content

itsgreggreg/haskell_quick_reference

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

82 Commits
 
 

Repository files navigation

Haskell Quick Reference

Tools

Primitive Data Types

Numbers

  • Written literally
  • All Integers are of type Num when written literally
  • Nums can be coerced into any Integer or Float type
  • All Floats are of type Fractional when written literally
  • Fractionals cannot be coerced to Integrs
> :t 1
1 :: Num t => t
> :t 1.5
1.5 :: Fractional t => t
> 10 == (10 :: Integer)
True
> 10 == 10.0
True
> 10.0 == (10 :: Integer)
error

Integers

  • Written literally as a series of didgits
  • Int for machine integers
  • Integer for arbitrary precision
  • Use Integer unless you know you need Int
> a = 10 :: Integer
> b = 3 :: Integer
> a / b               -- Connot use / to divide integers
error
> div a b             -- div for integer division
3
> rem a b             -- rem is modulus
1
> div a (3 :: Int)    -- Cannot mix int types
error
> :t fromIntegral a   -- Convert an Int(egral) type to a Num type
fromIntegral a :: Num b => b

Int

  • Implementations vary, guaranteed to be at least 30 bits.
> 9223372036854775807 :: Int
=> 9223372036854775807
> 9223372036854775808 :: Int
<interactive>:81:1: warning: [-Woverflowed-literals]
    Literal 9223372036854775808 is out of the Int range -9223372036854775808..9223372036854775807

Integer

  • Can hold values up to the memory limit of your machine
> 9223372036854775808 :: Integer
=> 9223372036854775808

Floats

  • Double for Double-precision floating point.
  • Float for Single-precision floating point. Often used when interfacing with C.
  • Use Double unless you know you need Float

Char

  • TODO Encoding

List

String

> let a = [1,2,3,4]
> Text.Printf.printf "the length of %s is %d\n" (show a) (length a)
> elem 1 [2,3,4]
False
> elem 1 [1,2,3]
True

Types

Creating types

Alias an Eixisting type

  • Creates merely an alias for an existing type.
  • Can make code more readable.
  • Can be used interchangeably with what is being aliased. Compiler don't care.
--    ┌ Age is simply an alias for Int, they can be used interchangeably
--
type Age = Int

From the standard lib:

type String = [Char] 
-- "String" is an alias for "List of Characters"

New Simple Type

  • Creates a brand new type.
  • It is common to name the Value Constructor the same as the Type Name
--       ┌ Type Name
--
newtype Age = 
  Age Int
-- ↑   └ What you must pass in to construct this type
-- └ Value Constructor

-- A function called "Age" that takes one "Int" now exists and it produces the value "Age some-int" 
-- which has a type of "Age"
  • Can take multiple paramaters
newtype Coordinates = 
  Coordinates Int Int
--            ↑    └ Paramater 2
--            └ Paramater 1

-- the function "Coordinates" now requires 2 paramaters an "Int" and another "Int" in
-- order to produce the value "Coordinates some-int some-int" of type "Coordinates"

Tagged Union

  • Simply a Type with multiple Value Constructors
  • It is common to name the Value Constructors differently than the Type Name
--    ┌ Type Name
--
data Pet 
  = Hamster Age 
  | Fish Age
--
--   └ "Tag" -or- "Type constructor"

-- Now the functions "Hamster" and "Fish" exist and they produce a value with the type of "Pet"

From the standard lib:

data Bool
  = True
  | False

Record Type

  • Simply a type who's value is a composite of many fields.
data Person = Person 
  { name :: String
  , age :: Age
  }

Type Variables

  • All of our types above are concrete -or- monomorphic.
  • To make a type definition polymorphic simply add a variable.

tagged union

--         ┌ Type Variable
--
data Maybe a
  = Nothing
  | Just a
--
--       └ The constructor "Just" can be passed a value of any type to produce a value of type "Maybe"

Type Classes

Functor

  • Generalizes function application over containers
  • <$> is the infix alias for fmap
  • a <$ b is the same as const a <$> b
  • Since Functor requires a kind of * -> * it must only work on 1 type variable
  • for (a, b) it works on b and leaves a unchanged.
  • for Either a b it works on b and leaves a unchanged.
class Functor (f :: * -> *) where
  fmap :: (a -> b) -> f a -> f b
  (<$) :: a -> f b -> f a
> fmap ((*) 2) [1,2,3]
-- [2,4,6]
> (*) 2 <$> [1,2,3]
-- [2,4,6]
> fmap ((*) 2) (Just 10)
-- Just 20
> fmap ((*) 2) (Left 10)
-- Left 10
> fmap ((*) 2) (Right 10)
-- Right 20
> fmap ((*) 2) (10,10)
-- (10, 20)

> "Hello" <$ Just 10
-- Just "Hello"
> Nothing <$ [1,2,3]
-- [Nothing,Nothing,Nothing]

Monoid

  • Generalizes how a strucutre should be associated with another structure of the same type
  • Must have an identity function mempty
class Monoid a where
  mempty :: a
  mappend :: a -> a -> a
  mconcat :: [a] -> a
> mempty
-- ()
> mempty :: [a]
-- []
> mappend [1,2,3] [4,5,6]
-- [1,2,3,4,5,6]
> mconcat [[1,2,3], [4,5], [6]]
-- [1,2,3,4,5,6]

Sometimes there isn't one clear way to associate structures of the same type and so you must be more specific. This is the case with Integral and you must use the more specific Sum Integral and Product Integral types.

> import Data.Monoid
> mempty :: Sum Int
-- Sum 0
> mappend (Sum 9) mempty
-- Sum 9
> mconcat [(Sum 3), (Sum 4)]
Sum 7
> mempty :: Product Int
-- Product 1
> mappend (Product 9) mempty
-- Product 9
> mconcat [(Product 3), (Product 4)]

Semigroup

  • Simply a monoid without an identity function
-- you must import Data.Semigroup to use
class Semigroup a where
  (Data.Semigroup.<>) :: a -> a -> a
  default (Data.Semigroup.<>) :: Monoid a => a -> a -> a
  sconcat :: Data.List.NonEmpty.NonEmpty a -> a
  stimes :: Integral b => b -> a -> a

Applicative

  • A way of generalizing a container of functions over a container of values
class Functor f => Applicative (f :: * -> *) where
 pure :: a -> f a
 (<*>) :: f (a -> b) -> f a -> f b
 GHC.Base.liftA2 :: (a -> b -> c) -> f a -> f b -> f c
 (*>) :: f a -> f b -> f b
 (<*) :: f a -> f b -> f a
 {-# MINIMAL pure, ((<*>) | liftA2) #-}
> pure 1 :: [Int]
-- [1]
> pure 1 :: Maybe Int
-- Just 1

> Nothing <*> Just 2
-- Nothing
> Just ((*) 4) <*> Nothing
-- Nothing
> Just ((*) 4) <*> Just 2
-- Just 8

> [minimum, maximum] <*> [[2,3,4], [5,6,7]]
-- [2,5,4,7]

> [1..10] *> [0,1]
-- [0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1]
> [1..10] <* [0,1]
-- [1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10]

> liftA2 (,) [1, 2] [3, 4] -- the same as (,) <$> [1,2] <*> [3,4]
-- [(1,3),(1,4),(2,3),(2,4)]

Monad

  • A way of chaining together wrapped operations that can fail
class Applicative m => Monad (m :: * -> *) where
  (>>=) :: m a -> (a -> m b) -> m b
  (>>) :: m a -> m b -> m b
  return :: a -> m a
  fail :: String -> m a
  {-# MINIMAL (>>=) #-}

Laws

Right Identity

m >>= return = m

Left Identity

return x >>= f = fx

Class

  • We define a typeclass with the class keyword.

Defining our own polymorphic equality (==) function:

class MyEq a where
    equal :: a -> a -> Bool
    
    notEqual :: a -> a -> Bool
    notEqual x y = not (equal x y)

Instance

  • We define implementations of the typeclass with the instance keyword
  • Since notEqual has a default implementation that depends on equal we only have to specify equal

Implementing equal for Bool:

instance MyEq Bool where
   equal True  True  = True
   equal False False = True
   equal _     _     = False

Syntax

Common Infix Functions

(.) : Function Composition

> :t (.)
-- (.) :: (b -> c) -> (a -> b) -> a -> c
> a = ((*) 2) . const 4
> a 123
-- 8
> a Nothing
-- 8

($) : Pipe Left

> :t ($)
-- ($) :: (a -> b) -> a -> b
> head $ map (*2) [13, 50, 1000]
-- 26

Defining Functions

Guards

  • The first guard that evaluates to true is run.
  • otherwise == true
  • If no guards match and there are no other function heads, you will get Exception: Non-exhaustive patterns in function myFun
myFilt :: (a -> Bool) -> [a] -> [a]
myFilt _ [] = []
myFilt f (x:xs)
  | f x       = x : myFilt f xs
  | otherwise = myFilt f xs
  
> myFilt even [1..10]
[2,4,6,8,10]


isFour :: (Eq a, Num a) => a -> Bool
isFour a
    | a == 4 = True
    
> isFour 4
True
> isFour 5
*** Exception: Non-exhaustive patterns in function isFour

List Comprehensions

> [ x ^ 2 | x <- [1..10]]
[1,4,9,16,25,36,49,64,81,100]
> [(x, y) | x <- [1..10], y <- [1..10], x > 7, y < 3]
[(8,1),(8,2),(9,1),(9,2),(10,1),(10,2)]
-- Remember, Strings are Lists
> [ x | x <- "This is Haskell", elem x ['A'..'Z']]
"TH"

Reserved Words

as case class data default deriving do else
family forall foreign hiding if import in infix
infixl infixr instance let mdo module newtype of
proc qualified rec then type where

Reserved Symbols

` ' " - -- -< -<< ->
:: ; <- , = => > ~
! ? # * @ [|, |] \ _
{, } {-, -} |

Quasi Quotes

  • Enabled per file with {-# LANGUAGE QuasiQuotes #-}
  • Enabled on the compiler with -XQuasiQuotes
  • Let you use/implement a DSL to write haskell
  • Follows format of [functionName| some-content |]
  • Are context aware so you can include bindings in scope

Truncated example for producing html in haskell with Yesod:

{-# LANGUAGE QuasiQuotes #-}
import Text.Hamlet (shamlet)

--                              ┌ Quasi Quoter called shamlet
--
main = putStrLn $ renderHtml [shamlet|
  <p>Hello, my name is #{name person} and I am 
    <strong> #{show $ age person}.
  |]
-- └ Close the quasi quotes
  where
    name = "Michael"
    age = 26
--
--   └ Bindings

Repl

  • Start by running ghci

If using Stack

  • Start the repl by running stack ghci or stack repl
  • Specify extra packages to include in the repl context with:
    • stack ghci --package regex-posix
    • and then import them with :m +Text.Regex.Posix

Useful Commands

  • :help -or- :h : Print a list of repl commands
  • :type some-value -or- :t some-value : Display type information for a value
  • :load some-module -or- :l some-module : Load a module into the repl
  • :reload -or- :r : Reload all loaded modules
  • :module -or- :m : Unload all loaded modules
> :t Nothing
Nothing :: Maybe a

> :t (round 1.5)
(round 1.5) :: Integral b => b

Blocks of code

  • delimited with :{ and :}
> :{
>  some_multi_line
>  expression
> :}

More Fun Stuff

About

A quick tour of Haskell and the Standard Lib

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published