Haskell

介绍 #

源于ML
标准化的、纯函数式编程语言
非限定性语义和强静态类型
作为其他语言设计新功能时的样板,如Python的lambda标记语句

工具 #

检索函数用http://www.Haskell.org/hoogle

单词 #

polymorphism
    # 多态
monomorphic
    # 单态

风格 #

point free style
    sum' xs = foldl (+) 0 xs
    sum' = foldl (+) 0

注意 #

使用缩进代替括号,但也可用括号

文件扩展名 #

# 文件中不用let定义变量, 
# 变量赋值两次会报错, 这意味着代码顺序不重要
hs

内置变量 #

pi

模块 #

:m Data.Char Data.Map
    # 加载模块
    chr
        # chr :: Int -> Char
    ord
        # ord :: Char -> Int
    toUpper
    toLower
import Data.Char
    # 导入到全局命名空间
    import Data.List (nub, sort)
    import Data.List hiding (nub)
    import qualified Data.Map as M
        # 这样其中命名冲突的filter, null函数,只能用Data.Map.filter或M.filter方式调用
可用模块
    prelude
        # 默认载入的模块
    Data
        Char
        List
        Map
        Set
自定义模块
module Geometry.Sphere
(sphereVolume
, sphereArea
, Shape(..)
    # 导出类型和其所有构造子
) where
sphereVolum :: Float -> Float
sphereVolum radius = (4.0 / 3.0) * pi * (radius ^ 3)

命令函数 #

:load
    # 加载模块
    :load a.hs
:l
:cd
    # 切换工作目录
    :cd c:\a
:reload
    # 重载所有模块
:r
:type
    :type 'H'
:t
:info
    # 查看一个typeclass有哪些instance和subclass
    # 类型的信息、函数的类型声明
:k
    # 查看kind
    :k Int
        # Int :: *
    :k Maybe
        # Maybe :: * -> *

操作符 #

%
    # 分号
&&
||
++    
    # 字符串拼接
/=
    # 不等
do
    # 动作的combine, do 是>>=的语法糖, 用来连接一系列动作
<-
    # name <- getLine, 存到变量
    # 除了程序的最后一行用来作返回值,其它语句都可以用 <-

表达式 #

# 表达式可以随处安放
if x < 0 then
    -1
else if x > 0 then
    1
else
    0

case x of
    0 -> 1
    1 -> 5
    _ -> (-1)

let a = 1
    # 局部绑定, in可省略则定义到全局
    twice_a = 2 * a
in (a + twice_a, a - twice_a)
    
let boot x  y z = x * y + z in boot 3 4 2

I/O action #

# 在main中 I/O action才被执行
# return () 语句产生I/O action, do接着执行
# 执行后会打印结果,结果为()时不打印
main = do
    _ <- putStrLn "a"
    name <- getLine
    putStrLn (name)

类型表示 #

Eq a => a -> a -> Bool
    # => 前面是类型约束, 后面表示传入两个同类型参数,返回Bool类型

变量 #

let pi = 3.14
    # 变量不可变,但可重复定义
(-1)
    # 负数一般加小括号
  let r = 25 :: Double
    # 默认猜测是Integer
    # monomorphish restriction(单一同态限定)原理,可以指定polymorphic(多态)
    ## let r = 25 :: Num a => a
True, False
    # 类型为 Bool
"abc"
    # 类型为[char], 与'a':'b':'c':[]
    a = "aaa" :: String
        # 得到一个String, 与[char]同样使用
LT, GT, EQ

函数 #

# 函数名与参数,参数与参数之间有空格隔开
# 函数比运算符先结合
let area r = pi * r ^ 2
    # 定义函数, 
area 2
area (-2)
let area2 r = area r
let first (x, y) = x
    # 接收元组
uppercase, lowercase :: String -> String
    # 指定函数类型
分段定义
    # 编译成case语句
    f 0 = 1
    f 1 = 5
    f _ = -1
函数合成调用
    square (f 1)
    (square . f) 1
(\xs -> length xs > 15)
    # lambda表达式
    # lambda可以用模式匹配,但使用不了多个模式

列表 #

# 列表,类型必须相同。
# 列表都由[]追加得到,逗号是语法糖
let n = [1, 2]
[1..20]
    # range浮点数不精确
take 20 [1,2..]
[2,4..20]
['a'..'z']
0:n
    # 得到追加列表[0, 1, 2], 头部追加叫作consing, cons是constructor
    # -1:0:n
[[1], [2]]
n !! 1
    # 取元素
l1 > l2
    # 元素依次比较
[x*2 | x <- [1..10], x*2 >= 12]
    # list comprehension
    boomBangs xs = [if x < 10 then "BOOM!" else "BANG!" | x <-xs, odd x]
    [x*y | x <-[1,2], y <-[3,4]]
        # 聚合得[3,4,6,8]
    length' xs = sum [1 | _ <- xs]

    xxs = [[1,2], [3,4]]
    [[x | x <- xs, even x] | xs <- xxs]

    [(a,b,c) | c <- [1..10], b <- [1..c], a <- [1..b], a^2 + b^2 = c ^2]

    [a + b | (a,b) <- xs]
        # list comprehension中的模式匹配
模式匹配
    x:xs
    x:y:z:xs

元组 #

# 类型可不同,不能单元素。2元组叫pairs, 3元组叫triples, n元组叫n-tuple
# 元组不可变
# 元组的类型由长度和其中的类型决定, ("a", 1)与(1, "a")是不同的类型,所以[("a", 1), (2, "b")]是错误的
(True, 1)
((1,2), True)

monad #

o-> do
doGuessing num = do
    putStrLn "Enter your guess:"
    guess <- getLine
    if (read guess) < num
    then do putStrLn "Too low"
        doGuessing num
    else if (read guess) > num
    then do putStrLn "Too high"
        doGuessing num
    else putStrLn "You Win"
        # 只有一个动作时,可省略do

o-> do
doGuessing num = do
    putStrLn "Enter your guess:"
    guess <- getLine
    case compare (read guess) num of
        LT -> do putStrLn "Too low"
        GT -> do putStrLn "Too high"
        EQ -> putStrLn "You Win"

o-> functor applicative monad
class Functor f where
fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where
pure :: a -> f a
() :: f (a -> b) -> f a -> f b
class Applicative m => Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
x >> y = x >>= \_ -> y
fail :: String -> m a
fail msg = error msg
instance Functor Maybe where
fmap func (Just x) = Just (func x)
fmap func Nothing  = Nothing
instance Applicative Maybe where
pure = Just
Nothing  _ = Nothing
(Just func)  something = fmap func something
instance Monad Maybe where
return = Just
Nothing >>= func = Nothing
Just x >>= func  = func x

内置函数 #

prelude
    $
        # 函数调用符,优先级最低。而空格是最高优先级
        # $右结合。而空格左结合
        # 等价于在右而写一对括号
    .
        # f . g = \x -> f (g x)
        # 函数组合
    main
        # main :: IO ()
        main = do
    signum
        # 根据数字返回 -1, 0, 1
    not
    id
        # identity
    unlines
        unlines ["a", "b"]
            # 成为 "a\nb\n"
    unwords
        unwords ["a", "b"]
            # 成为 "a b"
    show
        # 接受各种类型,转换为String, 再转义打印
    read
        read "5" :: Int
        read "5" - 2
        read "[1,2,3]" ++ [4]
    reads
        # 读取失败返回[]而不报错
    negate
        # 取反数字
    abs
        # 绝对值
    length
        # 列表的长度, [a] -> Int , a在这里是一个type variable, 以小写字母开头(具体类型都大写开头)。
    map
    compare
        # 返回 LT, GT, EQ其中一个
    min
    max
    compare
        # 返回LT, GT, EQ
        "Abc" `compare` "Zyx"
    mod
        # 取模
    odd
        # 奇数
    even
        # 偶数
    succ
        # 取Enum的后继
    pred
        # 取Enum的前置
    minBound
        # 取Bound下限
    maxBound
    substract
        # 减

    head
    tail
        # 除第一个
    last
    init
        # 除最后一个

    null
        # 检查list是否空
    reverse
        # list反转
    take
        take 1 [1,2,3]
    takeWhile
        # 取list值,直到某条件
    drop
        drop 1 [1,2,3]
    maximum
        # list中最大元素
    minimun
        # list中最小元素
    sum
        # list和
    product
        # list积
    elem
        # 判断元素是否在list中
        4 `elem` [3,4,5]
    cycle
        take 7 (cycle [1,2,3])
            # [1,2,3,1,2,3,1]
    repeat
        repeat 5
    replicate
        replicate 3 10
            # [10, 10, 10]

    fst (1, 2)
        # 只适合2元组
    snd (1, 2)
        # 只适合2元组
    zip
        # zip3, zip4 ... zip7
        zip [1,2,3] [4,5,6]
            # [(1,4), (2,5), (3,6)]
    zipWith
        # zipWith1 ... zipWith7
        zipWith (\x y -> x + y) [1,2] [3,4]
            # [4,6]
    fromIntegral
        # 返回更通用的数字类型
    error ""
        # 抛错
    flip
        # 翻转两个参数调用
    map
    filter
    foldl
        foldl (\acc x -> acc + x) 0 xs
    foldr
        foldr (\x acc -> f x : acc) [] xs
    foldl1
        # 以第一个元素为初始值,空list报错
    foldr1
    foldl'
        # foldl的strict版
    foldr'
    scanl
        # 返回累加过程的list
    scanr
    scanl1
    scanr1
    o-> I/O action
        # 只有在main中执行
        # 类型为 IO a
        putStrLn
            # 只接受String,不转义打印,加换行符
            # putStrLn :: String -> IO () , 表示接收String, 是IO动作, 结果类型是()。表示是一个"IO monad"动作
        putStr
            # 由putChar递归定义,边界条件是空字符串
        putChar
        print
            # 打印Show typeclass的值
        getLine
            # 控制台读一行
            # getLine :: IO String
            name <- getLine
        getChar
        sequence
        # 顺序执行I/O action
        mapM
            mapM print [1,2,3]
                # 对list元素执行sequence f
        mapM_
            # 同mapM,不打印[(),()]
        getContents
            # 读直到 eof (ctrl + d)
        interact
            # 用函数处理输入,返回到输出
Data.List
    # 每个元素存在thunk中
    \
        # 差集
        [1..3] \\ [2]
            # [1,3]
        "Im a big baby" \\ "big"
            # "Im a baby"
    union
    intersection
    insert
        # 插入一个元素到可排序list相对位置
    nub
        # 去重复元素,常用Set转换取代,提高很多效率
    map
        # 导出到了prelude
    filter
        # 导出到了prelude
    intersperse
        intersperse '.' "abc"
            # "a.b.c"
    intercalate
        # 同intersperse, 但插入list
    transpose
        # 二元list列为行
    foldl'
        # fold的严格版,直接计算出中间值,而非用惰性"承诺"塞满堆栈
    foldl1'
    concat
        # 移除一级嵌套
    concatMap
        # 先map再concat
        concatMap (replicate 2) [1..3]
            # [1,1,2,2,3,3]
    and
        # list中全true返回true
        and $ map (>4) [5,6,7,8]
    or
    any
    iterate
        # 无限迭代值到函数,结果形成list
        take 10 $ iterate (*2) 1
    splitAt
        # 断开list, 返回二元组
        splitAt 3 "abcdef"
            # ("abc", "def")
    takeWhile
        # 取元素,直到不符合条件
    dropWhile
    span
        # 同takeWhile, 不过返回分割list的二元组
    break
        # 同span, 但在条件首次为true时断开
    sort
        # list元素要求Ord类型,排序list
    group
        # 合并相邻并相等的list元素
    inits
        # init递归调用自身
        inits "abc"
            # ["", "a", "ab", "abc"]
    tails
        # tail递归调用自身
        tails "abc"
            # ["abc", "bc", "c", ""]
    isInfixOf
        # list中搜索子list, 有则返回true
        "cat" `isInfixOf` "im a cat"
    isPrefixOf
        # 是否以某list开头
    isSuffixOf
        # 是否以某list结尾
    elem
        # 是否包含某元素
    notElem
    partition
        # 条件划分list为二元组
        partition (`elem` ['A'..'Z']) "AbCD"
            # ("ACD", "b")
    find
        # 条件查找list, 返回第一个符合元素的Maybe值
    elemIndex
        # 返回elem第一个元素的索引的Maybe值
    elemIndices
        # 返回所有匹配索引的list
    findIndex
    findIndices
    lines
        # 字符串分行到list
    unlines
    words
        # 字符串分词到list
    unwords
    delete
        # 删除list中第一个匹配元素
        delete 'h' "hha"
            # "ha"
    replace
    lookup
        # 用a查找[('a', 'b')]中的b
    genericLength
        # 换Int类型为Num类型
    genericTake
    genericDrop
    genericSplitAt
    genericIndex
    genericReplicate

    nubBy
        # 传递函数判断相等性,取代==
    deleteBy
    unionBy
    intersectBy
    groupBy
    sortBy
    insertBy
    maximumBy
    minimumBy
Data.Monoid
    Monoid
    Product
    Sum
    Any
    All
Data.Foldable
    foldr
    foldl
    foldr1
    foldl1
Data.Function
    on
        ((==) `on` (> 0))
            # 判断相等性,等价于 (\x y -> (x > 0) == (y > 0))
        (compare `on` length)
            # 判断大小
Data.Char
    isControl
        # 是否控制字符
    isSpace
        # 包括空格, tab, 换行等
    isLower
    isUpper
    isAlpha
        # 是否字母
    isAlphaNum
        # 字母或数字
    isPrint
        # 可打印
    isDigit
    isOctDigit
    isHexDigit
    isLetter
        # 同isAlpha
    isMark
        # unicode注音字符
    isNumber
    isPunctuation
        # 是否标点符号
    isSymbol
        # 货币符号
    isSeperater
        # unicode空格或分隔符
    isAscii
        # unicode 前128位
    isLatin1
        # unicode 前256位
    isAsciiUpper
    isAsciiLower
    GeneralCategory
        # 得到字符的分类,一共31类, 属于Eq类型
        generalCategory ' '
            # Space
    toUpper
    toLower
    toTitle
    digitToInt
        # 数字,大小写字母list 转成 int list
    intToDigit
    ord
    char
Data.Map
    # 用avl树实现
    fromList
        # 重复键会忽略,要求key有相等性和排序性
    fromListWith
        # 重复键给函数处理
    toList
    empty
        # 返回空map
    insert
        insert 3 10 map
    insertWith
        # 已包含键时函数处理
    null
        # 检查map是否空
    size
        # 返回map的大小
    singleton
        singleton 3, 9
            # fromList [(3,9)]
    lookup
    member
        # key 是否在map中
    map
    filter
    keys
    elems
Data.Set
    # 要求元素可排序,自动排序、唯一
    # 用avl树实现
    fromList
    intersection
    difference
        # 存在于第一集合而不在第二集合的元素
    union
    null
    size
    member
    empty
    singleton
    insert
    delete
    isSubsetOf    
        # 子集
        fromList [1,2] isSubsetOf fromList [1,2]
    isProperSubsetOf
        # 真子集
    filter
    map
Data.ByteString
    # strict bytestring
    # Empty相当于[], cons相当于:
Data.ByteString.Lazy
    # 每个元素存在chunk中,每个chunk 64k,每个chunk相当于一个strict bytestring
    # cons在chunk不满的时候会新建chunk, cons'是strick版的cons, 会填充chunk
    pack
        # pack :: [Word8] -> ByteString
        pack [80,81]
    unpack
    fromChunks
        # 转换strick bytestring 到lazy
    toChunks
        # lazy转strick
Data.Ratio
Control.Applicative
    Applicative
        class (Functor f) => Applicative f where
            pure :: a -> fa
            (<*>) :: f (a -> b) -> f a -> f b
            f <$> x = fmap f x
    ZipList
        ZipList3
        ZipList7
    getZipList
    liftA2
        liftA2 f x y = f <$> x <*> y 
    sequenceA
Control.Monad
    when
        # Bool true时,返回后面的I/O action, 否则return ()
    forever
        # 不断执行后面的I/O action
        forever $ do
            putStr "a"
    forM
        # 同mapM, 但两个参数顺序相反
    liftM
        # monad中的fmap
    liftM2 liftM3 liftM4 liftM5
    `ap`
        # monad中的<*>
    join
        join :: (Monad m) => m (m a) -> m a
        join mm = do
            m <- mm
            m
    filterM
    foldM
Control.Monad.State
    State
        newtype State s a = State {runState :: s -> (a, s)}
    get
    put
Control.Monad.Error
System.IO
    openFile
        # openFile :: FilePath -> IOMode -> IO Handle
        # data IOMode = ReadMode | WriteMode | AppendMode | ReadWriteMode
        do
        handle = openFile "a.txt" ReadMode
        contents <- hGetContents handle
        putStr contents
        hClose handle
    withFile
        # withFile :: FilePath -> IOMode -> (Handle -> IO a) -> IO a
        # 处理完关掉
        withFile "a.txt" ReadMode (\handle -> do
            contents <- hGetContents handle
            putStr contents)
    readFile
        # readFile :: FilePath -> IO String
        do
        contents <- readFile "a.txt"
        putStr contents
    wirteFile
        # writeFile :: FilePath -> String -> IO ()
        do
        writeFile "a.txt" contents
    appendFile
    hSetBuffering
        # 读binary file时的buffer,默认是系统值
        # data BufferMode = NoBuffering | LineBuffering | BlockBuffering (Maybe Int)
        hSetBuffering handle $ BlockBuffering (Just 2048)
    hFlush
        # 写入时自动Flush
    openTempFile
        (tempName, tempHandle) <- openTempFile "." "temp"
    hGetContents
    hClose
    hGetLine
    hPusStr
    hPutStrLn
    hGetChar
System.IO.Error
    catch
        # catch :: IO a -> (IOError -> IO a) -> IO a
        toTry `catch` handler
        handler e
            | isDoesNotExistError e = 
                case ioeGetFileName e of Just path -> putStrLn $ "a" ++ path
                    Nothing -> putStrLn "b"
            | otherwise = ioError e
    isDoesNotExistError
    isAlreadyExistsError
    isFullError
    isEOFError
    isIllegalOperation
    isPermissionError
    isUserError
    ioeGetFileName
        # ioeGetFileName :: IOError -> Maybe FilePath
    ioError
        # 丢出接到的error
System.Directory
    removeFile
        removeFile "a.txt"
    renameFile
        renameFile tempName "a.txt"
    copyFile
    doesFileExist
System.Environment
    getArgs
    getProgName
System.Random
    mkStdGen
        # mkStdGen :: Int -> StdGen
    getStdGen
        # IO类型, 得到系统启动时的global generator
    newStdGen
        # 把现有的random generator分成两个新的generators, 其中一个指定成新的,返回另一个
    random
        # random :: (RandomGen g, Random a) = g -> (a, g)
        random (mkStdGen 100) :: (Int, StdGen)
    randoms
        take 5 $ randoms (mkStdGen 11) :: [Int]
    randomR
        # 区间random
        randomR (1,6) (mkStdGen 2)
    randomRs
        take 10 $ randomRs ('a', 'z') (mkStdGen 3) :: [Char]

函数 #

o-> 模式匹配
    # case的语法糖
    # 对构造子匹配,如 8 'a' : []
factorial :: (Integral a) => a -> a
factorial 0 = 1
factorial n = n * factorial (n - 1)

addVectors :: (Num a) => (a, a) -> (a, a) -> (a, a)
addVectors (x1, y1) (x2, y2) = (x1 + x2, y1 + y2)

first :: (a, b, c) -> a
first (x, _, _) = x

tell :: (Show a) => [a] -> String
tell [] = ""
tell [x: []] = ""
tell [x:y:[]] = ""
tell [x:y:_] = "too long, the first is " ++ show x ++ " and the second is " ++ show y

length' :: (Num b) => [a] -> b
length' [] = 0
length' (_:xs) = 1 + length' xs

capital :: String -> String
capital "" = ""
capital all@(x:xs) = "The first letter of " ++ all ++ " is " ++ [x]
    # @是as模式

o-> guard
bmiTell :: (RealFloat a) => a -> String
bmiTell weight height
    | bmi <= skinny = "You're underweight"
    | bmi <= normal = "You're supposedly normal"
    | bmi <= fat = "You're fat"
    | otherwise = "You're a whale"
    where bmi = weight / height ^ 2
    (skinny, normal, fat) = (18.5, 25.0, 30.0)
        # where是语法结构,不是表达式
calcBmis :: (RealFloat a) => [(a, a)] -> [a]
calcBmis xs = [bmi w h | (w, h) <- xs, let bmi = w / h ^ 2]

myCompare :: (Ord a) => a -> a -> Ordering
a `myCompare` b
    | a > b = GT
    | a == b = EQ
    | otherwise = LT

o-> quicksort
quicksort :: (Ord a) => [a] -> [a]
quicksort [] = []
quicksort (x:xs) = 
    let smallerSorted = quicksort (filter (<=x) xs)
        biggerSorted = quicksort [a | a <- xs, a > x]
    in smallerSorted ++ [x] ++ biggerSorted

o-> curry
compareWithHundred :: (Num a, ord a) => a -> Ordering
compareWithHundred = compare 100

divideByTen :: (Floating a) => a -> a
divideByTen = (/10)
    # 中缀函数用括号来不完全调用
    # 但(-4)表示负4, (substract 4)来表示减4函数

o-> 高阶函数
applyTwice :: (a -> a) -> a -> a
applyTwice f x = f (f x)

o-> lambda
addThree :: (Num a) => a -> a -> a -> a
addThree = \x -> \y -> \z -> x + y + z

o-> $ 做数据函数
map ($ 3) [(4+), (10*), (^2), sqrt]

类型 #

类型
    Int
        # 有界整数
    Integer
        # 无界整数
    Float
        # 单精度浮点数
    Double
    Bool
    Char
    Maybe
    []
    ()
    a
        # type variables
类型约束
    Eq
    # 可判断相等性的类型,可用 == 或 /= 判断
        # 只除函数
    Ord
        #可比较大小的类型, 必定是Eq
        # 只除函数
    Ordering
        # 只有GT, EQ, LT
    Show
        # 可用字符串表示的类型
        # 只除函数
    Read
        # 与Show相反
    Enum
        # 连续的类型,有后继子(successer)和前置子(predecesor), 分别通过succ函数和pred函数得到
        # 可以[1..2]构造list
        # 包含 (), Bool, Char, Ordering, Int, Integer, Float, Double
    Bounded
        # 有上限和下限
        # 如果Tuple中都属于Bounded, 那么这个Tuple属于Bounded
    Num
        # 数字特征
    Integral
        # 整数
    Floating
        # 浮点,包含Float和Double
构造类型
    data Bool = False | True deriving (Ord)
        # Bool是构造的类型, False为值构造子,值可以用:t查看其类型
        # 值构造子可以用于模式匹配
        # 这里值构造子是没有参数的,叫作nullary
        # False在True前,所以比较时True比False大
    data Point = Point Float Float deriving (Show)
        # 值构造子可以与类型同名
    data Shape = Circle Point Float | Rectangle  Point Point deriving (Show)
        # 派生自Show, 就可show值成字符串
    data Person = Person {firstName :: String
        , lastName :: String
        } deriving (Show)
            # Record Syntax, 同 Person String String,  但自动生成同名的取值函数,show显示也改变
        let p = Person {firstName="aa", lastName="bb"}
    
        tellPerson :: Person -> String
        tellPerson (Person {firstName = a, lastName = b}) = a ++ b
    newtype CharList = CharList {getCharList :: [Char]} deriving {Eq, Show}
        # newtype将现有类型包成新类型,只能定义单一值构造子,且其只能有一个字段。并将包裹和解开的成本都去掉
类型构造子
    # data声明中不能加类型约束
    data Maybe a = Nothing | Just a
    data Car a b = Car { company :: a
        , year :: b
        } deriving (Show)
    tellCar :: (Show a) => Car String a -> String
类型别名
    type String = [Char]
    type AssocList k v = [(k,v)]
        # 别名类型构造子
    type IntMap = Map Int
        # 不全调用得到不全类型构造子, 同 type intMap v = Map Int v
infixr
    infixr 5 :-:
        # 定义中缀构造子, 5是优先级, :-:是符号
        # 默认left-associative

    infixr 5 .++
    (.++) :: List a -> List a -> List a
    Empty .++ ys = ys
    (x :-: xs) .++ ys = x :-: (xs .++ ys)
recursive data structures
    data List a = Empty | a :-: (List a) deriving (Show, Read, Eq, Ord)
typeclass
    class Eq a where
        (==) :: a -> a -> Bool
        (/=) :: a -> a -> Bool
        x == y = not (x /= y)
        x /= y = not (x == y)
            # 只需要instance一个定义就好,这个定义叫minimal complete definition
    data TrafficLight = Red | Yellow | Green
    instance Eq TrafficLight where
        Red == Red = True
        Green == Green = True
        Yellow == Yellow = True
        _ == _ = False
    instance Show TrafficLight where
        show Red = "Red light"
        show Yellow = "Yellow light"
        show Green = "Green light"

    class (Eq a) => Num a where
        # Num 是 Eq  的 subclass, 要是Num必是Eq

    instance (Eq m) => Eq (Maybe m) where
        Just x == Just y = x == y
        Nothing == Nothing = True
        _ == _ = False
            
o-> Either
data Either a b = Left a | Right a deriving (Eq, Ord, Read, Show)

o-> Tree
data Tree a = EmptyTree | Node a (Tree a) (Tree a) deriving (Show, Read, Eq)

o-> YesNo
class YesNo a where
    yesno :: a -> Bool
instance YesNo Int where
    yesno 0 = False
    yesno _ = True

o-> Functor
class Functor f where
    # map over
    fmap :: (a -> b) -> f a -> f b
instance Functor Maybe where
    # 接收构造子而非类型
    fmap f (Just x) = Just (f x)
    fmap f Nothing = Nothing
instance Functor (Either a) where
    # parital apply Either, Either a 是个类型构造子
    fmap f (Right x) = Right (f x)
    fmap f (Left x) = Left x
instance Functor ((->) r) where
    # 对函数的functor
    fmap f g = (\x -> f (g x))

命令 #

ghci
    set prompt "ghci> "
        # 设置显示的提示符
ghc
    ghc --make a.hs
runhaskell
ghc-pkg list
    # 列出已安装的软件包

玄学 #

o->
:{
data X = X
a :: Int -> Int
a x = x + 3
:}