请使用以下代码:
{-# LANGUAGE DataKinds, GADTs #-}
module Lib where
import System.Random as Randy
someFunc :: IO ()
someFunc = dataKinds >>= \n -> putStrLn (show n)
data Kind a where
IntK :: Int -> Kind Int
StringK :: String -> Kind String
BoolK :: Bool -> Kind Bool
OtherK :: a -> Kind a
instance Show (Kind a) where
show (IntK n) = "KindInt " ++ show n
show (StringK s) = "KindString " ++ s
show (BoolK b) = "KindBool " ++ show b
dataKinds :: IO (Kind a)
dataKinds =
Randy.getStdRandom (Randy.randomR (1,6)) >>= \n ->
case n of
1 -> pure $ IntK n
2 -> pure $ IntK n
3 -> pure $ StringK (show n)
4 -> pure $ StringK (show n)
5 -> pure $ BoolK True
6 -> pure $ BoolK False
此代码无法编译,主要是因为编译器不喜欢pure $ IntK n
指定第一行返回Kind Int
但StringK
和{BoolK
的事实。最后四行返回{1}}:
• Couldn't match type ‘[Char]’ with ‘Int’
Expected type: IO (Kind Int)
Actual type: IO (Kind String)
• In the expression: pure $ StringK (show n)
这让我很奇怪。只需使用正常的data
声明,我就可以在没有GADT的情况下轻松完成此操作。但我曾假设像GADT这样的增强功能不会降低类型系统的灵活性,但会增加它。难道我做错了什么?我只是刚刚遇到这个扩展,所以我可能误解了一些东西。如何使用GADT编译程序?
答案 0 :(得分:4)
使xx
存在的Kind xx
类型存在(不会出现在返回类型中)
data SomeKind where
SomeKind :: Kind xx -> SomeKind
-- Only works because of: instance Show (Kind a)
-- Would not work with: instance Show a => Show (Kind a)
instance Show SomeKind where
show :: SomeKind -> String
show (SomeKind kind) = show kind
并实施dataKinds :: IO SomeKind
。
(使用dataKinds
实施fmap
)
(从Kind
中提取SomeKind
,我们可以编写Show
个实例吗?)
data Some :: (k -> Type) -> Type where
Some :: f xx -> Some f
instance ??? => Show (Some f) where
show :: Some f -> String
show (Some some) = show some
答案 1 :(得分:3)
您可能需要一个存在性包装器,例如
data SomeKind where
SomeKind :: Kind a -> SomeKind
dataKinds :: IO SomeKind
dataKinds =
Randy.getStdRandom (Randy.randomR (1,6)) >>= \n ->
case n of
1 -> pure . SomeKind $ IntK n
2 -> pure . SomeKind $ IntK n
3 -> pure . SomeKind $ StringK (show n)
4 -> pure . SomeKind $ StringK (show n)
5 -> pure . SomeKind $ BoolK True
6 -> pure . SomeKind $ BoolK False