Haskell笔记 (9)—— typeclass


> :t (==)
(==) :: Eq a => a -> a -> Bool

=>之前的Eq a表示:atypeEqtypeclassaEq的一个实例。

Typeclasses 101
Why sum x y is of type (Num a) => a -> a -> a in Haskell?
Explain Type Classes in Haskell


Haskell笔记 (8)—— 类型变量(type variables)


> :t head
head :: [a] -> a

这里的a不是typeHaskell中的类型以大写字母开头),而是type variale,可以代表任一类型,有点类似于其它编程语言的generics。含有type variable的函数称之为polymorphic functions

现在可以知道为什么type名字必须以大写字母开头,这是为了与type variable名字区分开。type variable必须以小写字母开头。 


You can always tell a type variable from a normal variable by context, because the languages of types and functions are separate: type variables live in type signatures, and regular variables live in normal expressions.

type variable存在于type signature中,而regular variable则存在于正常的表达式中。


Haskell笔记 (7)—— 类型


Haskell requires type names to start with an uppercase letter, and variable names must start with a lowercase letter.


> let C = "foo"

<interactive>:20:5: Not in scope: data constructor ‘C’
> let c = "foo"
> c
> :type c
c :: [Char]


The combination of :: and the type after it is called a type signature.


> :type 'a'
'a' :: Char

:: Char就被称之为type signature


Haskell笔记 (5)—— ghci


ghci stores the result of the last expression into a variable whose name is “it”. (This isn’t a Haskell language feature; it’s specific to ghci alone.)


> "foo"
> it ++ "bar"
> it

(2)可以使用:set <option>:unset <option>来设置和取消一些选项。以打印计算的结果类型为例:

> :set +t
> fst ('a', 'b')
it :: Char
> :unset +t
> fst ('a', 'b')


ghci> let a = 10
ghci> b = 100

<interactive>:9:3: parse error on input ‘=’


Haskell笔记 (4)—— 用前缀方法书写表达式

The infix style of writing an expression is just a convenience; we can also write an expression in prefix form, where the operator precedes its arguments. To do this, we must enclose the operator in parentheses.


ghci> 3 ^ 4
ghci> (^) 3 4
ghci> ^ 3 4

<interactive>:68:1: parse error on input ‘^’


Haskell笔记 (3)—— list和tuple


Because strings are lists, we can use list functions on them.


> "Hello " ++ "world"
"Hello world"


>let list = [1, 2, 3, 4]
> print list
> [5] : list

    Non type-variable argument in the constraint: Num [t]
    (Use FlexibleContexts to permit this)
    When checking that ‘it’ has the inferred type
      it :: forall t. (Num t, Num [t]) => [[t]]
> 5 : list


Ranges are a way of making lists that are arithmetic sequences of elements that can be enumerated. Numbers can be enumerated. One, two, three, four, etc. Characters can also be enumerated. The alphabet is an enumeration of characters from A to Z. Names can’t be enumerated. What comes after “John”?


> [1 .. 20]


> [2, 4 .. 20]


cycle takes a list and cycles it into an infinite list. If you just try to display the result, it will go on forever so you have to slice it off somewhere.

> take 10 (cycle [1,2,3])  
> take 12 (cycle "LOL ")  


repeat takes an element and produces an infinite list of just that element. It’s like cycling a list with only one element.

> take 10 (repeat 5)  


replicate function if you want some number of the same element in a list.

> replicate 10 5



>  [1,2]
> [1,2,]

<interactive>:12:6: parse error on input ‘]’


There’s a special type, () , that acts as a tuple of zero elements. This type has only one value, which is also written () . Both the type and the value are usually pronounced “unit.” If you are familiar with C, () is somewhat similar to void.


> :type fst
fst :: (a, b) -> a
> :type snd
snd :: (a, b) -> b


The list [1,2,3] in Haskell is actually shorthand for the list 1:(2:(3:[])), where [] is the empty list and : is the infix operator that adds its first argument to the front of its second argument (a list). (: and [] are like Lisp’s cons and nil, respectively.) Since : is right associative, we can also write this list as 1:2:3:[].

Haskell笔记 (2)—— if语句


The difference between Haskell’s if statement and if statements in imperative languages is that the else part is mandatory in Haskell.


doubleSmallNumber x = if x > 100
                      then x
                      else X * 2


parse error in if statement: missing required else clause


Another thing about the if statement in Haskell is that it is an expression. An expression is basically a piece of code that returns a value. 5 is an expression because it returns 5, 4 + 8 is an expression, x + y is an expression because it returns the sum of x and y. Because the else is mandatory, an if statement will always return something and that’s why it’s an expression.


Haskell笔记 (1)—— 函数


In Haskell, functions are called by writing the function name, a space and then the parameters, separated by spaces.


> min 9 10


If a function takes two parameters, we can also call it as an infix function by surrounding it with backticks.


> 9 `min` 10
> 9 min 10

    Non type-variable argument
      in the constraint: Num ((a -> a -> a) -> a -> t)
    (Use FlexibleContexts to permit this)
    When checking that ‘it’ has the inferred type
      it :: forall a a1 t.
            (Num a1, Num ((a -> a -> a) -> a1 -> t), Ord a) =>


Functions in Haskell don’t have to be in any particular order.


Side effects are essentially invisible inputs to, or outputs from, functions. In Haskell, the default is for functions to not have side effects: the result of a function depends only on the inputs that we explicitly provide. We call these functions pure; functions with side effects are impure.
If a function has side effects, we can tell by reading its type signature—the type of the function’s result will begin with IO:
ghci> :type readFile
readFile :: FilePath -> IO String
Haskell’s type system prevents us from accidentally mixing pure and impure code.


Haskell doesn’t have a return keyword, because a function is a single expression, not a sequence of statements. The value of the expression is the result of the function.