我正在根据字段名字符串扩展Haskell设置记录字段的答案?添加通用getField.我正在使用gmapQi,如果遇到的子元素的类型与预期的类型不匹配,我想生成错误.我希望错误消息包括遇到的类型的名称,以及预期类型的名称.该函数如下所示:
{-# LANGUAGE DeriveDataTypeable #-}
import Data.Generics
import Prelude hiding (catch)
import Control.Exception
getField :: (Data r, Typeable v) => Int -> r -> v
getField i r = gmapQi i (e `extQ` id) r
where
e x = error $ "Type mismatch: field " ++ (show i) ++
" :: " ++ (show . typeOf $ x) ++
", not " ++ (show . typeOf $ "???")
---------------------------------------------------------------------------------
data Foo = Foo Int String
deriving(Data, Typeable)
handleErr (ErrorCall msg) = putStrLn $ "Error -- " ++ msg
main = do
let r = Foo 10 "Hello"
catch (print (getField 0 r :: Int)) handleErr
catch (print (getField 0 r :: String)) handleErr
catch (print (getField 1 r :: Int)) handleErr
catch (print (getField 1 r :: String)) handleErr
Run Code Online (Sandbox Code Playgroud)
问题是,我不知道该取代"???"该getField函数的返回类型(即如何v从类型签名中进行验证).
typeOf永远不会评估它的参数,所以你可以使用任何表达式,只要它的类型正确.在这种情况下,结果的类型与返回类型相同e,因此您可以使用e x.
getField :: (Data r, Typeable v) => Int -> r -> v
getField i r = gmapQi i (e `extQ` id) r
where
e x = error $ "Type mismatch: field " ++ (show i) ++
" :: " ++ (show . typeOf $ x) ++
", not " ++ (show . typeOf $ e x)
Run Code Online (Sandbox Code Playgroud)
这在运行时给出了预期的输出:
10
"Error -- Type mismatch: field 0 :: Int, not [Char]
Error -- Type mismatch: field 1 :: [Char], not Int
"Hello"
Run Code Online (Sandbox Code Playgroud)