广义代数结构

代数结构就是普通的data,组合各个类型形成新的类型

1
data MyData = IntData Int | TextData Text

广义代数结构是一个语言拓展,开启广义代数数据类型

1
{-# LANGUAGE GADTs #-}

多参数构造子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{-# LANGUAGE GADTs #-}

module Lib
( someFunc
) where

data Expr a where
I :: Int -> Expr Int
B :: Bool -> Expr Bool
Add :: Expr Int -> Expr Int -> Expr Int

eval :: Expr a -> a
eval (I x) = x
eval (B x) = x
eval (Add x y) = eval x + eval y

someFunc :: IO ()
someFunc = do
let expr = Add (I 3) (I 4)
print (eval expr) -- 输出 7

能使用类型没有定义的变量

1
2
3
4
5
6
7
8
9
10
data DynamicSql where
ConstSql :: Text -> DynamicSql
-- 变量a并没有在DynamicSql类型中定义,也就是DynamicSql a
ValSql :: PersistField a => a -> DynamicSql
MaybeSql :: (a -> DynamicSql) -> Maybe a -> DynamicSql

parseDynamicSql :: DynamicSql -> (Text, [PersistValue])
parseDynamicSql (ConstSql txt) = (txt <> " ", [])
parseDynamicSql (ValSql val) = (" ? ", [toPersistValue val])
parseDynamicSql (MaybeSql dynamicSql' mVal) = maybe (" ", []) (parseDynamicSql . dynamicSql') mVal

应用

广义代数结构有些函数的性质,每一个值构造器都是一个逻辑的抽象,具体的实现由其他函数通过模式匹配的方式处理,如此可以针对一个类型提供多种实现。

以上方DynamicSql为例,DynamicSql是父接口,多个值构造器是子接口,parseDynamicSql为子接口提供实现。