GADT的功能

hom*_*mam 1 haskell gadt

这是函数到多态数据类型的后续问题

数据类型Question使用Message(问题文本)和String -> a将用户输入映射到问题结果的函数()模拟问题/答案:

data Question where
  Simple :: (Typeable a, Show a) => Message -> (String -> a) -> Question
Run Code Online (Sandbox Code Playgroud)

此CLI程序应首先获取其名称,Question使用getQuestion函数查找实例,然后运行Question并打印出结果.

{-# LANGUAGE GADTs #-}

import Data.Typeable

type Message = String

data Question where
  Simple :: (Typeable a, Show a) => Message -> (String -> a) -> Question
  -- more constructors

yourName :: Question
yourName = Simple "Your name?" id

yourWeight :: Question
yourWeight = Simple "What is your weight?" (read :: String -> Int)

getQuestion :: String -> Question
getQuestion "name" =  yourName
getQuestion "weight" =  yourWeight    

runQuestion :: (Typeable a, Show a) => Question -> IO a
runQuestion (Simple message parser) = do
  putStrLn message
  ans <- getLine
  return $ parser ans

main = getLine >>= (runQuestion . getQuestion) >>= print
Run Code Online (Sandbox Code Playgroud)

类型检查在这里失败:runQuestion :: (Typeable a, Show a) => Question -> IO awith No instance for (Typeable a0) arising from a use of ‘runQuestion’.

如果我删除类约束(runQuestion :: Question -> IO a)然后我得到No instance for (Show a0) arising from a use of ‘print.

n. *_* m. 5

这个类型

Question -> IO a
Run Code Online (Sandbox Code Playgroud)

表示"接受一个函数Question并返回一个函数,IO a 无论a调用者想要什么 ".这显然是错的; 一些问题有一个Int答案和一些有一个String答案,但毫无疑问有一个答案是可以按需Int,String或任何其他我们可能想.

如果您从答案中得到的只是表现自己的能力,那么只需将显示的答案作为答案IO String.

type Message = String

data Question = Simple Message (String -> String)
  -- more constructors

yourName :: Question
yourName = Simple "Your name?" show

yourWeight :: Question
yourWeight = Simple "What is your weight?" (show . (read :: String -> Int))

getQuestion :: String -> Question
getQuestion "name" =  yourName
getQuestion "weight" =  yourWeight

runQuestion :: Question -> IO String
runQuestion (Simple message parser) = do
  putStrLn message
  ans <- getLine
  return $ parser ans

main = getLine >>= (runQuestion . getQuestion) >>= putStrLn
Run Code Online (Sandbox Code Playgroud)

否则,您可以将存在性移动到答案中,您需要将其封装在新的GADT中:

type Message = String

data Question where
  Simple :: Message -> (String -> Answer) ? Question
  -- more constructors

data Answer where
  Easy ::  (Typeable a, Show a) => a -> Answer

instance Show Answer where
  show (Easy a) = show a

yourName :: Question
yourName = Simple "Your name?" Easy

yourWeight :: Question
yourWeight = Simple "What is your weight?" (Easy . (read :: String -> Int))

getQuestion :: String -> Question
getQuestion "name" =  yourName
getQuestion "weight" =  yourWeight

runQuestion :: Question -> IO Answer
runQuestion (Simple message parser) = do
  putStrLn message
  ans <- getLine
  return $ parser ans

main = getLine >>= (runQuestion . getQuestion) >>= print
Run Code Online (Sandbox Code Playgroud)

但这是恕我直言的矫枉过正.