构造方法技巧

HousePosition (houseBuilding form) (houseFloor form)如何使用monad简写

1
2
3
4
-- HousePosition :: Text -> Int -> HousePosition
-- houseBuilding :: Form -> Text
-- houseFloor :: Form -> Int
HousePosition <$> houseBuilding <*> houseFloor $ form

functor和Applicative

通过<$><*>进行简写,所以先了解函数的functor和applicative实现

functor于Applicative的签名如下

1
2
3
4
5
6
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

根据以上公式,函数的Functor和Applicative分别是

1
2
3
4
5
6
7
8
9
10
11
-- f1 <$> f2
-- f2结果作为f1的输入,得到f2的输入 -> f1 的结果
class Functor ((->) r) where
fmap :: (a -> b) -> ((->) r) a -> ((->) r) b

-- f1 <*> f2
-- 不考虑f1的第一个参数
-- f2的结果作为f1的第二个参数,得到f2的输入 -> f1的结果
class Functor ((->) r) => Applicative ((->) r) where
pure :: a -> f a
(<*>) :: ((->) r) (a -> b) -> ((->) r) a -> ((->) r) b

推导

处理HousePosition houseBuilding的关系

  • HousePosition: Text -> (Text -> HousePosition )
  • houseBuilding: Form -> Text

houseBuilding的结果Text可以作为HousePosition的参数Text

所以,将HousePosition函数应用于houseBuilding的结果

得到HousePosition <$> houseBuilding

1
2
3
4
5
Text -> Text -> HousePosition 
<$>
Form -> Text
=
Form -> (Text -> HousePosition)

处理(HousePosition <$> houseBuilding)houseFloor的关系

  • (HousePosition <$> houseBuilding): Form -> Int -> HousePosition
  • houseFloor: Form -> Int

houseFloor的结果可以作为(HousePosition <$> houseBuilding)的第二个参数

所以,将(HousePosition <$> houseBuilding)函数去掉第一个参数后应用于houseBuilding的结果

得到HousePosition <*> houseBuilding

1
2
3
4
5
6
7
-- 去掉第一个参数得到 Int -> HousePosition
Form -> Int -> HousePosition
<*>
-- 结果Int 将被函数Int -> HousePosition取代
Form -> Int
=
Form -> HousePosition

提升

其实就是一个提升操作,原先的构造函数是Text -> Int -> HousePosition,经过提升后变成Form -> HousePosition