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
In the above code I have a lambda with a very polymorphic type foldl (\f s -> getn s >>= f). From what I can tell, this causes it to not typecheck in its following recursions.
I think that I can use the RankNTypes language extension for my purpose to define a polymorphic recursive type that can represent any partial application of a function and, hence, allow the function to typecheck. With experimentation, much trial and equal amounts of error, though, I have been unable to come up with anything which compiles.
I would be very grateful if somebody can show me how to implement the RankNTypes extension in terms of the example code above (or suggest alternatives). I'm using GHC 7.4.2.
What you are trying to do is not possible. The typechecker does not know how many elements are in the list, and thus how many arguments you are trying to pass to the constructor. You do, but that is irrelevant in a statically checked language.
RankNTypes is not going to help because the root problem is not the type of your lambda (even if that is where the typechecker throws the error. The problem is with your accumulator: foldl has type (a -> b -> a) -> a -> [b] -> a; Note, in particular, that no matter how many extensions you throw at the typechecker, the accumulator must have the same type at each point in the fold. Test has type Int -> Bool -> String -> Test; its first partial application has type Bool -> String -> Test, and there is no way to unify those types.
If the rest of your program is well-typed, however, you should be able to use simply liftM3 Test (getn "field1") (getn "field2") (getn "field3") as your return, which is little more verbose and far clearer than what you were attempting.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With