这是函数到多态数据类型的后续问题
数据类型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.
这个类型
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)
但这是恕我直言的矫枉过正.