GADT 的 - 应用程序和有用性?
GADT's - applications and usefulness?
我正在使用 learnyouahaskell 介绍 GADT,我对它们的可能用途很感兴趣。我知道他们的主要特点是允许显式类型设置。
如:
data Users a where
GetUserName :: Int -> Users String
GetUserId :: String -> Users Int
usersFunction :: Users a -> a
usersFunction (GetUserName id)
| id == 100 = "Bob"
| id == 200 = "Phil"
| otherwise = "No corresponding user"
usersFunction (GetUserId name)
| name == "Bob" = 100
| name == "Phil" = 200
| otherwise = 0
main = do
print $ usersFunction (GetUserName 100)
除了在使用这些数据类型时增加额外的类型安全性外,GADT 的其他用途是什么?
Glambda
Richard Eisenberg 在 glambda
a simply typed lambda calculus interpreter which uses GADTs to make sure ill-typed programs simply cannot be constructed. Phil Wadler has something similar and simpler here 中为 GADT 提出了一个非常有说服力的案例,以下示例就是从中提取的
data Exp e a where
Con :: Int -> Exp e Int
Add :: Exp e Int -> Exp e Int -> Exp e Int
Var :: Var e a -> Exp e a
Abs :: Typ a -> Exp (e,a) b -> Exp e (a -> b)
App :: Exp e (a -> b) -> Exp e a -> Exp e b
想法是表达式的类型(在解释器中)被编码为 Haskell 程序中表示的表达式类型。
根据长度输入的向量
通过使用 GADT,我们可以添加一个虚拟类型,告诉我们跟踪我们拥有的向量的长度。 This 包有一个很好的实现。这可以通过多种方式重新实现(例如使用 GHC.TypeLits
类型级自然数)。有趣的数据类型(从链接的包的来源复制)是
data Vector (a :: *) (n :: Nat) where
Nil :: Vector a Z
(:-) :: a -> Vector a n -> Vector a (S n)
然后,我可以写一个head' :: Vector a (S n) -> a
的安全版本。
约束
我没有很好的示例来证明它的用处,但是您可以在 GADT 中对各个构造函数施加约束。当您构造某些东西时,您在构造函数上添加的约束会被强制执行,并且在您进行模式匹配时可用。这让我们可以做各种有趣的事情。
data MyGADT b where
SomeShowable :: Show a => a -> b -> MyGADT b -- existential types!
AMonad :: Monad b => b -> MyGADT b
我正在使用 learnyouahaskell 介绍 GADT,我对它们的可能用途很感兴趣。我知道他们的主要特点是允许显式类型设置。
如:
data Users a where
GetUserName :: Int -> Users String
GetUserId :: String -> Users Int
usersFunction :: Users a -> a
usersFunction (GetUserName id)
| id == 100 = "Bob"
| id == 200 = "Phil"
| otherwise = "No corresponding user"
usersFunction (GetUserId name)
| name == "Bob" = 100
| name == "Phil" = 200
| otherwise = 0
main = do
print $ usersFunction (GetUserName 100)
除了在使用这些数据类型时增加额外的类型安全性外,GADT 的其他用途是什么?
Glambda
Richard Eisenberg 在 glambda
a simply typed lambda calculus interpreter which uses GADTs to make sure ill-typed programs simply cannot be constructed. Phil Wadler has something similar and simpler here 中为 GADT 提出了一个非常有说服力的案例,以下示例就是从中提取的
data Exp e a where
Con :: Int -> Exp e Int
Add :: Exp e Int -> Exp e Int -> Exp e Int
Var :: Var e a -> Exp e a
Abs :: Typ a -> Exp (e,a) b -> Exp e (a -> b)
App :: Exp e (a -> b) -> Exp e a -> Exp e b
想法是表达式的类型(在解释器中)被编码为 Haskell 程序中表示的表达式类型。
根据长度输入的向量
通过使用 GADT,我们可以添加一个虚拟类型,告诉我们跟踪我们拥有的向量的长度。 This 包有一个很好的实现。这可以通过多种方式重新实现(例如使用 GHC.TypeLits
类型级自然数)。有趣的数据类型(从链接的包的来源复制)是
data Vector (a :: *) (n :: Nat) where
Nil :: Vector a Z
(:-) :: a -> Vector a n -> Vector a (S n)
然后,我可以写一个head' :: Vector a (S n) -> a
的安全版本。
约束
我没有很好的示例来证明它的用处,但是您可以在 GADT 中对各个构造函数施加约束。当您构造某些东西时,您在构造函数上添加的约束会被强制执行,并且在您进行模式匹配时可用。这让我们可以做各种有趣的事情。
data MyGADT b where
SomeShowable :: Show a => a -> b -> MyGADT b -- existential types!
AMonad :: Monad b => b -> MyGADT b