import Data.ConfigFile
data Test = Test
{ field1 :: Int
, field2 :: Bool
, field3 :: String
} deriving (Show)
whatMyConfigLooksLike =
[ ("field1", "5")
, ("field2", "True")
, ("field3", "I am a string")
]
options = fst . unzip $ whatMyConfigLooksLike
readConfigFile = do
rv <- runErrorT $ do
cp <- join . liftIO $ readfile emptyCP "theconfig.cfg"
let printn = liftIO . putStrLn
getn = get x "DEFAULT"
x = cp
printn "Loading configuration file..."
-- I don't want to do the following
one <- getn "field1"
two <- getn "field2"
three <- getn "field3"
return $ Test one two three -- ...
-- ... and so on because I have a data type with many fields
-- I want to fold them onto the data constructor instead
return $ foldl (\f s -> getn s >>= f) (Test) options
-- but I think this doesn't type check because f's type is constantly changing?
print rv
在上面的代码中,我有一个具有非常多态类型的 lambdafoldl (\f s -> getn s >>= f)
。据我所知,这会导致它在接下来的递归中不进行类型检查。
我认为我可以使用 RankNTypes 语言扩展来定义一个多态递归类型,该类型可以表示函数的任何部分应用,从而允许函数进行类型检查。然而,通过实验、大量的尝试和同等数量的错误,我一直无法想出任何可以编译的东西。
如果有人可以向我展示如何根据上面的示例代码实现 RankNTypes 扩展(或建议替代方案),我将非常感激。我正在使用 GHC 7.4.2。
你想做的事是不可能的。类型检查器不知道列表中有多少元素,因此也不知道您尝试将多少参数传递给构造函数。确实如此,但这对于静态检查语言来说是无关紧要的。
RankNTypes 不会有帮助,因为根本问题不是你的 lambda 的类型(即使这是类型检查器抛出错误的地方。问题出在你的累加器上:foldl
有类型(a -> b -> a) -> a -> [b] -> a
;请特别注意,无论您向类型检查器抛出多少扩展,累加器在折叠中的每个点都必须具有相同的类型。Test
有类型Int -> Bool -> String -> Test
;它的第一个部分应用程序具有类型Bool -> String -> Test
,并且没有办法统一这些类型。
但是,如果程序的其余部分类型正确,您应该能够简单地使用liftM3 Test (getn "field1") (getn "field2") (getn "field3")
作为您的返回,这比您尝试的内容更详细,也更清晰。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)