在Haskell中使用GADT返回多态类型

时间:2018-01-19 12:21:58

标签: haskell

请使用以下代码:

{-# 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 IntStringK和{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编译程序?

2 个答案:

答案 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