类型类练习题

为黄总精心设计,不要谢我,请我喝奶茶、吃榨菜即可。

第一题

给一下数据类型:

data MilkTea =
{ hasBoba :: Bool
, cupSize :: Int
} deriving Show

手工定义 Eq 实例。

给出以下值的类型:

hasBoba
cupSize

定义函数 view, set, lHasBoba 并满足以下不变量:

view lHasBoba :: MilkTea -> Bool
view lHasBoba tea = hasBoba tea
set lHasBoba :: Bool -> MilkTea -> MilkTea
set lHasBoba x tea = tea { hasBoba = x }

提示,可以定义数据类型 LHasBoba 如下:

data LHasBoba = LHasBoba
{ view :: MilkTea -> Bool
, set :: Bool -> MilkTea -> MilkTea
}
lHasBoba = LHasBoba
{ view = ...
, set = ...
}

上述的 LHasBoba 被称为 lens。试定义一个通用的 Lens:

data Lens s a = Lens
{ view :: s -> a
, set :: a -> s -> s
}

并给出 lHasBoba 与 lCupSize

第二题

class Functor f where
fmap :: (a -> b) -> f a -> f b

见阅读材料。

给出以下数据类型的 Functor 实例:

data Maybe a = Just a | Nothing
data [a] = a : [a] | []
data Tree a = Leaf a | Branch (Tree a) (Tree a)
data Identity a = Identity { runIdentity :: a }
data Const a = Const { runConst :: a }

不得使用 DeriveFunctor 扩展。


Lens s a 还可以定义为:

type Lens s a = forall f. Functor f => (a -> f a) -> s -> f s

注:需要打开扩展 RankNTypes,自行谷歌 GHC 开启扩展的方法。

根据上述 Lens 定义,重新定义 view 与 set。提示:使用 Identity 和 Const。

第三题

第二题陈述了一个事实,这两种 Lens s a 的定义同构,即存在如下两个函数:

data Lens s a = Lens
{ view :: s -> a
, set :: a -> s -> s
}
type Lens' s a = formal f. Functor f => (a -> f a) -> s -> f s
lensToLens' :: Lens s a -> Lens' s a
lens'ToLens :: Lens' s a -> Lens s a

试给出两者定义。

第四题

data Expr = Lit Int
| Add Expr Expr
| Mul Expr Expr

定义以下函数:

eval :: Expr -> Int
Show your support

Clapping shows how much you appreciated Liu Minsheng’s story.