Haskell笔记 (9)—— typeclass

Typeclass顾名思义:typeclass,类型的分类,同Java中的interface类似。参看下例:

> :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)—— 类型

(1)

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
"foo"
> :type c
c :: [Char]

(2)

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

举例如下:

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

:: Char就被称之为type signature

 

Haskell笔记 (5)—— ghci

(1)

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"
"foo"
> it ++ "bar"
"foobar"
> it
"foobar"

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

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

(3)在ghci中定义变量与源文件中定义变量不一样,需要在变量前加上let

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
81
ghci> (^) 3 4
81
ghci> ^ 3 4

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

 

Haskell笔记 (3)—— list和tuple

(1)

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

举例如下:

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

(2)
:用来连接一个元素和list++连接两个list

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

<interactive>:23:1:
    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
[5,1,2,3,4]

(3)

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]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]

也可以指定元素之间的“步长”(24之间差2):

> [2, 4 .. 20]
[2,4,6,8,10,12,14,16,18,20]

另外,cycle循环一个list

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])  
[1,2,3,1,2,3,1,2,3,1]  
> take 12 (cycle "LOL ")  
"LOL LOL LOL "   

repeat循环一个元素

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)  
[5,5,5,5,5,5,5,5,5,5]  

也可以使用replicate函数:

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

> replicate 10 5
[5,5,5,5,5,5,5,5,5,5]

(4)

list最后一个元素后面不能再跟,

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

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

(5)

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.

(6)fstsnd这两个函数只能操作包含两个元素的tuple

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

(7)

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语句

(1)

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

Haskell中,if语句的else部分是必须有的:

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

否则会有以下编译错误:

parse error in if statement: missing required else clause

(2)

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)—— 函数

(1)

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

Haskell中函数调用不使用括号,使用空白符隔开函数名和参数:

> min 9 10
9

(2)

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

如果函数有两个参数,可以使用中缀表达法。但要注意“`”符号:

> 9 `min` 10
9
> 9 min 10

<interactive>:10:1:
    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) =>
            t

(3)

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

(4)

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.

(5)

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.