Monday, November 28, 2011

Snap: Haskell Web Framework

http://snapframework.com/docs/quickstart
http://snapframework.com/docs/tutorials/snap-api

  1. cabal update
  2. cabal install snap  -- installs into C:\Users\<user>\AppData\Roaming\cabal  (or $HOME/.cabal/) (10mins)
  3. mkdir snapblog
  4. cd snapblog
  5. snap init -- creates .ghci, snapblog.cabal, <src>, <log>, <resources>
  6. cabal install  -- installs executable snap (snapblog.exe) into C:\Users\<user>\AppData\Roaming\cabal\bin  (or $HOME/.cabal/bin)
  7. snapblog -p 8000

Comparing Type Classes with Other Languages

Difference between Typeclasses and Java Interfaces
  • Interfaces methods are always associated with an object instance. In other words, there is always an implied 'this' parameter that is the object on which the method is called. All inputs to a type class function are explicit.
  • An interface implementation must be defined as part of the class that implements the interface. Conversely, a type class 'instance' can be defined completely seperate from its associated type...even in another module.
  • A type class allows you to define a 'default' implementation for any of the defined operations. Interfaces are strictly type specifications only, no implementation.
  • Type classes were created as a structured way to express "ad-hoc polymorphism" [non-OO], which is basically the technical term for overloaded functions. A type class definition looks something like this:
  • class Foobar a where
        foo :: a -> a -> Bool
        bar :: String -> a
    • What this means is that, when you use apply the function foo to some arguments of a type that belong to the class Foobar, it looks up an implementation of foo specific to that type, and uses that. 
    • This is very similar to the situation with operator overloading in languages like C, except more flexible and generalized.
  • Interfaces serve a similar purpose in OO languages, but the underlying concept is somewhat different; OO languages come with a built-in notion of type hierarchies that Haskell simply doesn't have, which complicates matters in some ways because interfaces can involve both overloading by subtyping (i.e., calling methods on appropriate instances, subtypes implementing interfaces their supertypes do) and by flat type-based dispatch (since two classes implementing an interface may not have a common superclass that also implements it). Given the huge additional complexity introduced by subtyping, I suggest it's more helpful to think of type classes as an improved version of overloaded functions in a non-OO language.
  • Also worth noting is that type classes have vastly more flexible means of dispatch -- interfaces generally apply only to the single class implementing it, whereas type classes are defined for a type, which can appear anywhere in the signature of the class's functions. The equivalent of this in OO interfaces would be allowing the interface to define ways to pass an object of that class to other classes, define static methods and constructors that would select an implementation based on what return type is required in calling context, define methods that take arguments of the same type as the class implementing the interface, and various other things that don't really translate at all.
  • They serve similar purposes, but the way they work is somewhat different, and type classes are both significantly more expressive and, in some cases, simpler to use because of working on fixed types rather that pieces of an inheritance hierarchy.
  • Methods are bound to an object, Haskell typeclasses are not.
  • Type classes were originally developed to deal with ad-hoc polymorphism
    such as operator overloading in a less ad-hoc manner
  • A type class defines a signature for a family of functions
    that every member of the type class must implement
  • Eq is parameterized in a single type, a
  • A type becomes a member of a type class by an instance declaration that implements
    the functions declared in the type class
  • data Nat = Zero | Succ Nat
    • The type Nat becomes a member of the type class Eq as follows:
      instance Eq Nat where −− Structural equality
      Zero == Zero = True
      Zero == (Succ ) = False
      (Succ ) == Zero = False
      (Succ x) == (Succ y) = x == y

data Point = FloatPoint Float Float
           | IntPoint Int Int
Haskell provides a very easy way to build/analyze them:
coord :: Point -> (Float, Float)
coord (FloatPoint x y) = (x,y)
coord (IntPoint x y) = (realToFrac x, realToFrac y)
 
main = do print (coord (FloatPoint 1 2))
          print (coord (IntPoint 1 2))
So ADTs in general are preferred in Haskell over the class-based solution of the same problem:
class Point a where
    coord :: a -> (Float, Float)
 
data FloatPoint = FloatPoint Float Float
instance Point FloatPoint where
    coord (FloatPoint x y) = (x,y)
 
data IntPoint = IntPoint Int Int
instance Point IntPoint where
    coord (IntPoint x y) = (realToFrac x, realToFrac y)



Comparison to Other Languages.

The classes used by Haskell are similar to those used in other object-oriented languages such as C++ and Java. However, there are some significant differences:
  • Haskell separates the definition of a type from the definition of the methods associated with that type. A class in C++ or Java usually defines both a data structure (the member variables) and the functions associated with the structure (the methods). In Haskell, these definitions are separated.
  • The class methods defined by a Haskell class correspond to virtual functions in a C++ class. Each instance of a class provides its own definition for each method; class defaults correspond to default definitions for a virtual function in the base class.
  • Haskell classes are roughly similar to a Java interface. Like an interface declaration, a Haskell class declaration defines a protocol for using an object rather than defining an object itself.
  • Haskell does not support the C++ overloading style in which functions with different types share a common name.
  • The type of a Haskell object cannot be implicitly coerced; there is no universal base class such as Object which values can be projected into or out of.
  • C++ and Java attach identifying information (such as a VTable) to the runtime representation of an object. In Haskell, such information is attached logically instead of physically to values, through the type system.
  • There is no access control (such as public or private class constituents) built into the Haskell class system. Instead, the module system must be used to hide or reveal components of a class.


Compared with Scala's Implicit Defs
http://blog.tmorris.net/the-power-of-type-classes-with-scala-implicit-defs/

Sunday, November 20, 2011

LYAH Chapter 3 - Types and Typeclasses


Chapter 3: Types and Typeclasses

Explicit Type Declaration
Common Haskell Types
Type Variables
Type Classes 101
The Eq Type Class
The Ord Type Class
The Show Type Class
The Read Type Class
The Enum Type Class
The Bounded Type Class.
The Num Type Class
The Floating Type Class
The Integral Type Class
Some Final Notes on Type Classes


Believe the type

A type is a kind of label/category that every expression has.  True is a boolean, "hello" is a string, etc.
Functions also have types. When writing our own functions, we can choose to give them an explicit type declaration. This is generally considered to be good practice except when writing very short functions.
Common types.

  • Int stands for integer. Int is bounded, which means that it has a minimum and a maximum value. Usually on 32-bit machines the maximum possible Int is 2147483647 and the minimum is -2147483648.
  • Integer stands for, er … also integer. The main difference is that it's not bounded so it can be used to represent really really big numbers. I mean like really big. Int, however, is more efficient.
    • factorial :: Integer -> Integer  
    • factorial n = product [1..n]  
    • ghci> factorial 50  --> 30414093201713378043612608166064768844377641568960512000000000000 
  •  Float is a real floating point with single precision.
    • circumference :: Float -> Float  
    • circumference r = 2 * pi * r  
    • ghci> circumference 4.0  --> 25.132742  
  • Double is a real floating point with double the precision!
    • circumference' :: Double -> Double  
    • circumference' r = 2 * pi * r  
    • ghci> circumference' 4.0  --> 25.132741228718345  
  • Bool is a boolean type. It can have only two values: True and False.
  • Char represents a character. It's denoted by single quotes. A list of characters is a string.
  • Tuples are types but they are dependent on their length as well as the types of their components, so there is theoretically an infinite number of tuple types, which is too many to cover in this tutorial. 
  • Note that the empty tuple () is also a type which can only have a single value: ()

Type variables

  • Types are written in capital case, type variable start with a lowercase
  • ghci> :t head  -->  head :: [a] -> a 
    • a can be of any type. 
    • This is much like generics in other languages, only in Haskell it's much more powerful because it allows us to easily write very general functions if they don't use any specific behavior of the types in them. 
    • Functions that have type variables are called polymorphic functions
    • The type declaration of head states that it takes a list of any type and returns one element of that type.
    • Although type variables can have names longer than one character, we usually give them names of a, b, c, d …
  • ghci> :t fst  --> fst :: (a, b) -> a   
    • We can use fst on a pair that contains any two types. 
    • Just because a and b are different type variables, they don't have to be different types. 

Typeclasses 101

  • A typeclass is a sort of interface that defines some behavior. 
  • If a type is a part of a typeclass, that means that it supports and implements the behavior the typeclass describes. 
  • A lot of people coming from OOP get confused by typeclasses because they think they are like classes in object oriented languages. Well, they're not. 
  • You can think of them kind of as Java interfaces, only better.
  • Eq
    • ghci> :t (==)  -->  (==) :: (Eq a) => a -> a -> Bool  
    • Everything before the => symbol is called a class constraint
    • "The equality function takes any two values that are of the same type and returns a Bool. The type of those two values must be a member of the Eq class (class constraint)."
    • The Eq typeclass provides an interface for testing for equality. Any type where it makes sense to test for equality between two values of that type should be a member of the Eq class. 
    • All standard Haskell types except for IO (the type for dealing with input and output) and functions are a part of the Eq typeclass.
    • The elem function has a type of (Eq a) => a -> [a] -> Bool because it uses == over a list to check whether some value we're looking for is in it.
  • If a function is comprised only of special characters, it's considered an infix function by default 
Basic Typeclasses
  • Eq is used for types that support equality testing. 
    • The functions its members implement are == and /=
    • So if there's an Eq class constraint for a type variable in a function, it uses == or /= somewhere inside its definition. 
    • All the types we mentioned previously except for functions are part of Eq, so they can be tested for equality.
    • class Eq a where
        (==) :: a -> a -> Bool
  • Ord is for types that have an ordering.
    • ghci> :t (>)  -->  (>) :: (Ord a) => a -> a -> Bool  
    • All the types we covered so far except for functions are part of OrdOrd covers all the standard comparing functions such as >,<>= and <=. The compare function takes two Ord members of the same type and returns an ordering. Ordering is a type that can be GTLT or EQ, meaning greater thanlesser than and equal, respectively.
    • To be a member of Ord, a type must first have membership in the prestigious and exclusive Eq club.   class Eq a => Ord a
      • ghci> "Abrakadabra" < "Zebra"  -->  True  
      • ghci> "Abrakadabra" `compare` "Zebra"  -->  LT  
  • Show  Members of can be presented as strings.
    • All types covered so far except for functions are a part of Show
    • The most used function that deals with the Show typeclass is show
    • It takes a value whose type is a member of Show and presents it to us as a string.
      • ghci> show 3  --> "3"  
      • ghci> show 5.334  --> "5.334"  
      • ghci> show True  --> "True"  
  • Read is sort of the opposite typeclass of Show. The read function takes a string and returns a type which is a member of Read.
    • ghci> read "True" || False  -->  True  
    • ghci> read "8.2" + 3.8  -->  12.0  
    • ghci> read "5" - 2  -->  3  
    • ghci> read "[1,2,3,4]" ++ [3]  -->  [1,2,3,4,3]  
    • So far so good. Again, all types covered so far are in this typeclass. But what happens if we try to do just read "4"?
      • ghci> read "4"  
      • <interactive>:1:0:  
      •     Ambiguous type variable `a' in the constraint:  
      •       `Read a' arising from a use of `read' at <interactive>:1:0-7
      • Probable fix: add a type signature that fixes these type variable(s)  
    • What GHCI is telling us here is that it doesn't know what we want in return. Notice that in the previous uses of read we did something with the result afterwards. That way, GHCI could infer what kind of result we wanted out of our read. If we used it as a boolean, it knew it had to return a Bool. But now, it knows we want some type that is part of the Read class, it just doesn't know which one. Let's take a look at the type signature of read.
      • ghci> :t read  -->  read :: (Read a) => String -> a  
    • See? It returns a type that's part of Read but if we don't try to use it in some way later, it has no way of knowing which type. That's why we can use explicit type annotations. Type annotations are a way of explicitly saying what the type of an expression should be. We do that by adding :: at the end of the expression and then specifying a type. 
      • ghci> read "5" :: Int  --> 5  
      • ghci> read "5" :: Float  --> 5.0  
      • ghci> (read "5" :: Float) * 4  --> 20.0  
      • ghci> read "[1,2,3,4]" :: [Int]  --> [1,2,3,4]  
      • ghci> read "(3, 'a')" :: (IntChar) --> (3'a')  
    • Most expressions are such that the compiler can infer what their type is by itself. But sometimes, the compiler doesn't know whether to return a value of type Int or Float for an expression like read "5". To see what the type is, Haskell would have to actually evaluate read "5". But since Haskell is a statically typed language, it has to know all the types before the code is compiled (or in the case of GHCI, evaluated). So we have to tell Haskell: "Hey, this expression should have this type, in case you don't know!".
  • Enum members are sequentially ordered types — they can be enumerated. 
    • The main advantage of the Enum typeclass is that we can use its types in list ranges. 
    • They also have defined successors and predecesors, which you can get with the succ and predfunctions. 
    • Types in this class: ()BoolCharOrderingIntIntegerFloat and Double.
    • ghci> ['a'..'e']  --> "abcde"  
    • ghci> [LT .. GT]  --> [LT,EQ,GT]  
    • ghci> [3 .. 5]  -->  [3,4,5]  
    • ghci> succ 'B'  -->  'C'  
  • Bounded members have an upper and a lower bound.
    • ghci> minBound :: Int  -->  -2147483648  
    • ghci> maxBound :: Char  -->  '\1114111'  
    • ghci> maxBound :: Bool  -->  True  
    • ghci> minBound :: Bool  -->  False  
    • minBound and maxBound are interesting because they have a type of (Bounded a) => a. In a sense they are polymorphic constants.
    • All tuples are also part of Bounded if the components are also in it.
      • ghci> maxBound :: (BoolIntChar)  -->  (True,2147483647,'\1114111'
  • Num is a numeric typeclass. Its members have the property of being able to act like numbers. 
    • ghci> :t 20  -->  20 :: (Num t) => t  
    • It appears that whole numbers are also polymorphic constants. They can act like any type that's a member of the Num typeclass.
      • ghci> 20 :: Int  -->  20  
      • ghci> 20 :: Integer  -->  20  
      • ghci> 20 :: Float   -->   20.0  
      • ghci> 20 :: Double   -->  20.0  
    • Those are types that are in the Num typeclass. If we examine the type of *, we'll see that it accepts all numbers.
      • ghci> :t (*)   -->   (*) :: (Num a) => a -> a -> a  
    • It takes two numbers of the same type and returns a number of that type. That's why (5 :: Int) * (6 :: Integer) will result in a type error whereas 5 * (6 :: Integer) will work just fine and produce an Integer because 5 can act like an Integer or anInt.
    • To join Num, a type must already be friends with Show and Eq.
  • Integral is also a numeric typeclass. Num includes all numbers, including real numbers and integral numbers, Integralincludes only integral (whole) numbers. In this typeclass are Int and Integer.
  • Floating includes only floating point numbers, so Float and Double.
  • fromIntegral A very useful function for dealing with numbers
    • It has a type declaration offromIntegral :: (Num b, Integral a) => a -> b
    • From its type signature we see that it takes an integral number and turns it into a more general number. 
      • That's useful when you want integral and floating point types to work together nicely. 
      • For instance, thelength function has a type declaration of length :: [a] -> Int instead of having a more general type of(Num b) => length :: [a] -> b
      • I think that's there for historical reasons or something, although in my opinion, it's pretty stupid. 
    • If we try to get a length of a list and then add it to 3.2, we'll get an error because we tried to add together an Int and a floating point number. So to get around this, we do fromIntegral (length [1,2,3,4]) + 3.2 and it all works out.


Topics Introduced

  • Types
  • Type Variables
  • Type Classes
  • Class constraints
  • Type annotations
  • "Polymorphic constants"



Type summary
·         Int on 32-bit machines the maximum possible Int is 2147483647 and the minimum is -2147483648.
·         Integer not bounded, Int is more efficient.
·         Float is a real floating point with single precision.
·         Double is a real floating point with double the precision
·         Bool is a boolean type. It can have only two values: True and False.
·         Char represents a character. It's denoted by single quotes. A list of characters is a string.
·         Tuples - infinite number of tuple types. The empty tuple () is also a type which can only have a single value: ()

Typeclass function summary

  • Eq 
    • == and /=
  • Ord 
    • >, <, >= and <=
    • compare, max, min 
  • Show 
    • show, showList, showsPrec
  • Read 
    • read, readList, readsPrec
  • Enum 
    • succ, pred
    • can use its types in list ranges
  • Bounded 
    • minBound and maxBound 
  • Num 
    • (+), (*), (-), negate, abs, signum, fromInteger
  • Integral includes only integral (whole) numbers. 
    • In this typeclass are Int and Integer.
  • Floating includes only floating point numbers, so Float and Double.
  • fromIntegral()


Questions

  • Why is succ 1.1 == 2.1 ??
  • Why is pred 1.1 == 0.10000000000000009 ??
  • If you do 5 * (6 :: Integer) Haskell infers the type of 5 to be Integer... how does Haskell convert the 5 to Integer?   Using (5 :: Integer) ??
  • What can you do with :: ?
  • How do you create a polymorphic constant like Bounded or 2::Int ??
  • How does a type become part of a typeclass?   instance, deriving

Explain the following:
  • class -- defines a type class
  • data -- defines an algebraic data type
  • instance -- make a datatype part of a typeclass, defining your own behaviour
  • deriving  -- make a datatype part of a typeclass, deriving default behaviour based on constituent types