Haskell笔记1
1. 类型
类型 | 例 |
|
lists | ghci> head [1,2,3,4]1 ghci> head ['a','b','c']'a' |
|
tuples | ghci> (1964, "Labyrinths") (1964,"Labyrinths") |
|
2. 函数
函数 | 例 |
|
take | ghci> take 2 [1,2,3,4,5] [1,2] |
|
drop | ghci> drop 3 [1,2,3,4,5] [4,5] |
|
fst | ghci> fst (1,'a') 1 |
|
snd | ghci> snd (1,'a') 'a' |
|
head | ghci> head (drop 4 "azerty") 't' |
|
lines | ghci> lines "the quick\nbrown fox\njumps" ["the quick","brown fox","jumps"] |
|
null | ghci> :type null null :: [a] -> Boolghci> :type (||)(||) :: Bool -> Bool -> Bool |
|
mod | isOdd n = mod n 2 == 1 |
|
| ghci> print (myDrop 2 "abcd")"cd" |
|
last | ghci> last [1,2,3,4,5] 5 ghci> last "baz" 'z' |
|
3. 逻辑语句
分支和循环 | 例 |
|
If..then..else | myDrop n xs = if n <= 0 || null xs then xs else myDrop (n - 1) (tail xs) | We'll refer to the expressions after the then and else keywords as “branches”. The branches must have the same types; the if expression will also have this type. An expression such as if True then 1 else "foo" has different types for its branches, so it is ill typed and will be rejected by a compiler or interpreter. Recall that Haskell is an expression-oriented language. In an imperative language, it can make sense to omit the else branch from an if, because we're working with statements, not expressions. However, when we're working with expressions, an if that was missing an else wouldn't have a result or type if the predicate evaluated to False, so it would be nonsensical. |
4. Ghci环境
函数 | 例子 |
|
:load | ghci> :load add.hs [1 of 1] Compiling Main ( add.hs, interpreted ) Ok, modules loaded: Main. |
|
:cd | ghci> :cd /tmp |
|
:type | ghci> :type lines lines :: String -> [String] ghci> :type last last :: [a] -> a |
|
5. 其他
概念 | 解释 |
|
结合性 | In Haskell, function application is left associative. This is best illustrated by example: the expression a b c d is equivalent to (((a b) c) d). It's pretty clear that there's something going on with an Int and some lists, but why are there two -> symbols in the signature? Haskell groups this chain of arrows from right to left; that is, -> is right-associative. If we introduce parentheses, we can make it clearer how this type signature is interpreted. |
|
等号 | When you see an = symbol in Haskell code, it represents “meaning”: the name on the left is defined to be the expression on the right. |
|
函数的纯洁性 | A side effect introduces a dependency between the global state of the system and the behaviour of a function. For example, let's step away from Haskell for a moment and think about an imperative programming language. Consider a function that reads and returns the value of a global variable. If some other code can modify that global variable, then the result of a particular application of our function depends on the current value of the global variable. The function has a side effect, even though it never modifies the variable itself. 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 |
|
imperative language | Python,perl |
|
variable | In Haskell, a variable provides a way to give a name to an expression. Once a variable is bound to (i.e. associated with) a particular expression, its value does not change: we can always use the name of the variable instead of writing out the expression, and get the same result either way. |
|
Polymorphism | When a function has type variables in its signature, indicating that some of its arguments can be of any type, we call the function polymorphic. |
|
subtype polymorphism | Since Haskell isn't an object oriented language, it doesn't provide subtype polymorphism. |
|
parametric polymorphism | This kind of polymorphism is called parametric polymorphism. |
|
coercion polymorphism | Also common is coercion polymorphism, which allows a value of one type to be implicitly converted into a value of another type. Many languages provide some form of coercion polymorphism: one example is automatic conversion between integers and floating point numbers. Haskell deliberately avoids even this kind of simple automatic coercion. |
|
type signature | We can now write a type signature for the myDrop function that we defined earlier. -- file: ch02/myDrop.hs myDrop :: Int -> [a] -> [a] |
|
6. 高级
概念 | 解释 |
|
Lazy evaluation | In Haskell, the subexpression 1 + 2 is not reduced to the value 3. Instead, we create a “promise” that when the value of the expression isOdd (1 + 2) is needed, we'll be able to compute it. The record that we use to track an unevaluated expression is referred to as a thunk. This is all that happens: we create a thunk, and defer the actual evaluation until it's really needed. If the result of this expression is never subsequently used, we will not compute its value at all. |
|
Short circuiting | Many languages need to treat the logical-or operator specially so that it short circuits if its left operand evaluates to True. In Haskell, (||) is an ordinary function: non-strict evaluation builds this capability into the language. |
|
thunk | The result of applying a function may be a thunk. |
|