I'm making a Yesod subsite and am getting a type error in some Template Haskell-generated code:
Yesod\DataSource\Data.hs:19:1:
Couldn't match type `[Char]' with `Text'
Expected type: () -> ([Text], [(Text, Text)]) -> Maybe (Route DataSource)
Actual type: () -> ([[Char]], [(Text, Text)]) -> Maybe (Route DataSource)
In the first argument of `\ f_amMs x_amMt -> f_amMs () x_amMt ::
forall a_amMu.
(() -> ([Text], [(Text, Text)]) -> Maybe (Route a_amMu))
-> ([Text], [(Text, Text)]) -> Maybe (Route a_amMu)', namely
`helper_amMr'
In the expression:
\ f_amMs x_amMt -> f_amMs () x_amMt ::
forall a_amMu.
(() -> ([Text], [(Text, Text)]) -> Maybe (Route a_amMu))
-> ([Text], [(Text, Text)]) -> Maybe (Route a_amMu)
helper_amMr
The problem is clear, but I don't understand why it's generating incorrect code.
The issue occurs in this TH call:
mkYesodSubData "DataSource" [parseRoutes|
/ SubHomeR GET
/datasource DataSourceInputR POST GET
|]
Specifically, it is caused by the line:
/datasource DataSourceInputR POST GET
Removing this line fixes the issue.
I'm using Stackage LTS 1.15:
remote-repo: stackage-lts-1.15:http://www.stackage.org/snapshot/lts-1.15
And I'm inside a cabal sandbox.
Here are the relevant files: https://gist.github.com/BeerendLauwers/774cc432c3ada5b597e1
Any idea?
I think that the generated code expects that you have the OverloadedStrings extension enabled in your source file. Try adding
{-# LANGUAGE OverloadedStrings #-}
to the top of the source file where you splice in the Template Haskell code (i.e. Data.hs).
Related
I am working on OAuth2 authentication for a Yesod application and I am having a type error that I really really don't understand. The code is broken at the moment, and I have a few :: IO ()'s and undefineds thrown around to help me isolate the type error, but the relevant code is:
getAccessToken :: Manager -> OAuth2 -> ExchangeToken -> IO (OAuth2Result Errors OAuth2Token)
getAccessToken manager oa code = do
let (uri, defaultBody) = accessTokenUrl oa code
let body = defaultBody <> [ ("client_id", TE.encodeUtf8 . oauthClientId $ oa )
, ("client_secret", TE.encodeUtf8 . oauthClientSecret $ oa)
, ("resource", TE.encodeUtf8 . oauthClientId $ oa)
]
response <- performOAuth2PostRequest manager oa uri body
return undefined
performOAuth2PostRequest :: Manager -> OAuth2 -> URI -> PostBody -> IO (Response ByteString)
performOAuth2PostRequest manager oa uri body = do
defaultReq <- uriToRequest uri
let addBasicAuth = applyBasicAuth (TE.encodeUtf8 . oauthClientId $ oa)
(TE.encodeUtf8 . oauthClientSecret $ oa)
let req = (addBasicAuth . updateRequestHeaders Nothing) defaultReq
(httpLbs (urlEncodedBody body req) manager) :: IO (Response ByteString)
Notice that I am specifically setting the type of the httpLbs (urlEnc...) manager action as an IO (Response ByteString) using the ScopedTypeVariables extension. Also, that line of code should be an IO action because it's being performed at the top level of an IO action.
In fact, I ran a GHCi session and did:
Network.OAuth.OAuth2.HttpClient Network.OAuth.OAuth2.Internal
Network.HTTP.Conduit Data.Functor Prelude> :t httpLbs
httpLbs
:: Control.Monad.IO.Class.MonadIO m =>
Request
-> Manager -> m (Response Data.ByteString.Lazy.Internal.ByteString)
Which confirms my understanding that httpLbs should yield a MonadIO m => m (Response ByteString).
But here is the error I get:
• Couldn't match type ‘Response
Data.ByteString.Lazy.Internal.ByteString’
with ‘IO (Response ByteString)’
Expected type: Manager -> IO (Response ByteString)
Actual type: Manager
-> Response Data.ByteString.Lazy.Internal.ByteString
• The function ‘httpLbs’ is applied to two arguments,
its type is ‘Request
-> m1 (Response Data.ByteString.Lazy.Internal.ByteString)’,
it is specialized to ‘Request
-> Manager -> Response Data.ByteString.Lazy.Internal.ByteString’
Why is GHC specializing m to Response instead of IO? How do I fix it?
You haven't included your import statements, making it difficult to debug this. My best guess though is that you've imported Network.HTTP.Simple, which provides functions that do not require an explicit Manager argument. I'm guessing this from the error message providing the expected type:
Request -> m1 (Response Data.ByteString.Lazy.Internal.ByteString)
Solution: either change the import, or drop the Manager argument.
GHC is saying my function is too general to be passed as an argument.
Here is a simplified version that reproduces the error:
data Action m a = SomeAction (m a)
runAction :: Action m a -> m a
runAction (SomeAction ma) = ma
-- Errors in here
actionFile :: (Action IO a -> IO a) -> String -> IO ()
actionFile actionFunc fileName = do
actionFunc $ SomeAction $ readFile fileName
actionFunc $ SomeAction $ putStrLn fileName
main :: IO ()
main =
actionFile runAction "Some Name.txt"
This is what the error says:
• Couldn't match type ‘a’ with ‘()’
‘a’ is a rigid type variable bound by
the type signature for:
actionFile :: forall a. (Action IO a -> IO a) -> String -> IO ()
at src/Lib.hs:11:15
Expected type: Action IO a
Actual type: Action IO ()
The compiler wants me to be more specific in my type signature, but I can't because I will need to use the parameter function with different types of arguments. Just like in my example I pass it an Action IO () and an Action IO String.
If I substitute (Action IO a -> IO a) -> String -> IO () for (Action IO () -> IO ()) -> String -> IO (), like the compiler asked, the invocation with readFile errors because it outputs an IO String.
Why is this happening and what should I do to be able to pass this function as an argument?
I know that if I just use runAction inside my actionFile function everything will work, but in my real code runAction is a partially applied function that gets built from results of IO computations, so it is not available at compile time.
This is a quantifier problem. The type
actionFile :: (Action IO a -> IO a) -> String -> IO ()
means, as reported by the GHC error,
actionFile :: forall a. (Action IO a -> IO a) -> String -> IO ()
which states the following:
the caller must choose a type a
the caller must provide a function g :: Action IO a -> IO a
the caller must provide a String
finally, actionFile must answer with an IO ()
Note that a is chosen by the caller, not by actionFile. From the point of view of actionFile, such type variable is bound to a fixed unknown type, chosen by someone else: this is the "rigid" type variable GHC mentions in the error.
However, actionFile is calling g passing an Action IO () argument (because of putStrLn). This means that actionFile wants to choose a = (). Since the caller can choose a different a, a type error is raised.
Further, actionFile also wants to call g passing an Action IO String argument (because of readFile), so we also want to choose a = String. This implies that g must accept the choice of whatever a we wish.
As mentioned by Alexis King, a solution could be to move the quantifier and use a rank-2 type:
actionFile :: (forall a. Action IO a -> IO a) -> String -> IO ()
This new type means that:
the caller must provide a function g :: forall a. Action IO a -> IO a
the caller of g (i.e., actionFile) must choose a
the caller of g (i.e., actionFile) must provide an Action IO a
finally, g must provide an IO a
the caller must provide a String
finally, actionFile must answer with an IO ()
This makes it possible to actionFile to choose a as wanted.
(UPDATED)
I have made an interface using a Free Monad to a generic data store. I want to place the specific interpreter (:: DataStore a -> IO a) chosen by the user at run time into a state monad along with some other information. I cannot seem to put anything into this field in the data structure.
How do I put a value into a field defined as a higher rank type?
Below is a minimum example:
{-# LANGUAGE RankNTypes, DeriveFunctor #-}
data ProgramState = PS { -- line 3
[...]
, storageInterface :: (forall a. DataStore a -> IO a)
}
data DataStoreF next =
Create Asset ( String -> next)
| Read String ( Asset -> next)
| Update Asset ( Bool -> next)
| UpdateAll [Asset] ( Bool -> next)
| [...]
deriving Functor
type DataStore = Free DataStoreF
runMemory :: (IORef (Map String Asset)) -> DataStore a -> IO a
runMemory ms (Pure a) = return a
runMemory ms (Free Create asset next) = [...]
runMemory ms (Free Read str next) = [...]
[...]
pickStorageInterface :: IO (DataStore a -> IO a)
pickStorageInterface = do
opts <- parseOptions
case (storage opts) of
MemoryStorage ->
ms <- readAssetsFromDisk
return $ runMemory ms
SomeOtherStorage -> [...]
restOfProgram :: StateT ProgramState IO
restOfProgram = [...]
main = do
si <- pickStorageInterface
let programState = PS { storageInterface = si} -- line 21
evalState restOfProgram programState
When I try to do this GHC complains that:
Main.hs: << Line 21 >>
Couldn't match type `a0' with `a'
because type variable `a' would escape its scope
This (rigid, skolem) type variable is bound by
a type expected by the context: DataStore a -> IO a
at Main.hs <<line 3>>
Expected type: DataStore a -> IO a
Actual type: DataStore a0 -> IO a0
In the `storageInterface' field of a record
[...]
UPDATE
My original minimal example was to minimal. Some further experimentation shows that the problem arises when I need to load the interface in an the IO monad so I can read the command line options. I've updated the example to include that issue. Knowing this I may be able to code around it.
Interesting GHCI tells me that the results of a function of type IO (DataStore a -> IO a) is DataStore GHC.Prim.Any -> IO GHC.Prim.Any which is not what I expected.
The issue here is that
pickStorageInterface :: forall a. IO (DataStore a -> IO a)
while we would need the (impredicative) type
pickStorageInterface :: IO (forall a. DataStore a -> IO a)
for the code above to work. Alas, the impredicative types are in a sad state now in GHC, and are best to be avoided.
You can work around that using a newtype wrapper around the universally quantified type:
newtype SI = SI { runSI :: forall a. DataStore a -> IO a }
pickStorageInterface :: IO SI
pickStorageInterface = do
opts <- parseOptions
case (storage opts) of
MemoryStorage ->
ms <- readAssetsFromDisk
return $ SI $ runMemory ms
...
main = do
si <- pickStorageInterface
let programState = PS { storageInterface = runSI si}
...
I am try to pass a parameter to a route at runtime inside a hamlet template.
buildFeedRow :: Item [Attribute Text] -> GWidget a a ()
buildFeedRow item = do
let f = unpackItem item
u :: Text = url f
[whamlet|
<tr>
<td>
<a href="#{url f}">#{url f}
<td>#{nextCrawlTime f}
<td>#{crawlDelay f}
<td>
<a href="#{DeleteFeedR u}">Delete
<td>Edit |]
It fails with a type error.
Couldn't match type `Route a' with `ConsoleRoute'
Expected type: ConsoleRoute -> [(Text, Text)] -> Text
Actual type: Route a -> [(Text, Text)] -> Text
Expected type: GHandler
a a (ConsoleRoute -> [(Text, Text)] -> Text)
Actual type: GGHandler
a
a
(Data.Enumerator.Iteratee Data.ByteString.Internal.ByteString IO)
(Route a -> [(Text, Text)] -> Text)
In the first argument of `lift', namely `getUrlRenderParams'
In the first argument of `(>>=)', namely `lift getUrlRenderParams'
My question is how do you pass parameters to routes in a hamlet template.
I think the the type signature of your widget might be too generic. Since you're using a route, it now depends on your foundation type so it should have the type
buildFeedRow :: Item [Attribute Text] -> GWidget YourFoundation YourFoundation ()
I'm working on ffi bindings to the Assimp library using c2hs. I have a datatype AiScene, defined as follows (the details are unimportant):
data AiScene = AiScene
{ mFlags :: SceneFlags
, mMeshes :: [AiMesh]
, mMaterials :: [AiMaterial]
, mAnimations :: [AiAnimation]
, mTextures :: [AiTexture]
, mLights :: [AiLight]
, mCameras :: [AiCamera]
}
{#pointer *aiScene as AiScenePtr -> AiScene#}
Now I'm trying to write bindings to the following function:
const aiScene* aiImportFile(
const char* pFile,
unsigned int pFlags);
This is what I have so far:
{#fun aiImportFile as ^
{`String', cFromEnum `SceneFlags'} -> `AiScene' peek*#}
Unfortunately I get a type error...
Couldn't match expected type `AiScene' against inferred type `()'
Expected type: IO AiScene
Inferred type: IO ()
Now if I go into the generated source and change the type:
aiImportFile'_ :: ((Ptr CChar) -> (CUInt -> (IO (Ptr ())))) -- original
aiImportFile'_ :: ((Ptr CChar) -> (CUInt -> (IO (Ptr AiScene)))) -- fixed
Then the problem goes away. How can I get c2hs to do this automatically / what am I doing wrong?
Thanks!
Edit: One thing I forgot to mention is that I have defined an instance of Storable for AiScene.
community-wiki answer with the solution for posterity:
I defined the following: with' x y = with x (y . castPtr) and peek' = peek . castPtr and the type errors go away.