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.
Related
I have a call like someFunc #'SomeX #'SomeY .... Is there some aliasing syntax to make it shorter? Something like:
type ??? = #'SomeX #'SomeY
someFunc #??? ...
?
Your example is very vague, but one thing you can do is to redefine someFunc with a more precise type:
someFunc :: a -> b -> a
someFunc x y = x
someFunc' :: Int -> Bool -> Int
someFunc' = someFunc
Then you can use someFunc' whenever you would previously write someFunc #Int #Bool.
Alternatively, if you only really care about that second #'SomeY argument, then you can use the snail: someFunc #_ #'SomeY. In this case the compiler will automatically try to fill in that underscore type application.
Sorry for asking another question about this dice game :).
I've got the following code:
--type GepakteStenen = [Steen]
--data Tactiek = Tactiek
-- {tactiekPakken ::GepakteStenen -> Worp -> IO Steen
--, tactiekDoorgaan ::GepakteStenen -> IO Bool
-- }
tactiekUitv :: Worp -> GepakteStenen -> Predicaat -> IO(Steen,Bool)
tactiekUitv w g p = do s <- (tactiekPakken g w)
let gs = g ++ filter (s==) w
if (magStoppen p gs) then
return (s,tactiekDoorgaan gs)
else
return (s,True)
Where i get this error message:
Couldn't match expected type `Tactiek' with actual type `[Steen]'
Why is it that i am giving the right type to my "tactiekDoorgaan" function, it wants me to create that a Tactiek of that?
This declaration
data Tactiek = Tactiek
{ tactiekPakken :: GepakteStenen -> Worp -> IO Steen
...
makes tactiekPakken a three argument function
tactiekPakken :: Tactiek -> GepakteStenen -> Worp -> IO Steen
-- ^^^^^^^ --
because there is a first, implicit argument having your record type. this might be confusing at first, but after all, we can not access a record field without having a record value at hand.
In your code, you do not provide the implicit Tactiek argument
do s <- (tactiekPakken g w)
-- ^^^^^^^^^^^^^^ --
(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}
...
Sorry for asking as potentially silly question, but returning to Haskell to do some conversion from one database package to a different one, I find myself a bit puzzled about how to do this properly.
In the Database.SQLite3 module, there is an execWithCallback with type
execWithCallback :: Database -> Text -> ExecCallback -> IO ()
Now, the callback is defined as
type ExecCallback = ColumnCount -> [Text]-> [Maybe Text] -> IO ()
that is, a function with type ExecCallback
My silly test code compiles and runs correctly:
{-# LANGUAGE OverloadedStrings #-}
import Database.SQLite3
import Data.Text
cb :: ColumnCount -> [Text] -> [Maybe Text] -> IO ()
cb n cnl ct = do print $ cnl !! 1
return ()
main = do
dh <- open "fileinfo.sqlite"
execWithCallback dh "select * from files;" cb
close dh
but then, what is the point of the type??? And, how do I specify that cb is an ExecCallback??
In Haskell, with type you define a type synonym. In your example that means that ExecCallback is just an alias for the type ColumnCount -> [Text]-> [Maybe Text] -> IO (), they are interchangeable.
You could change the following lines
cb :: ColumnCount -> [Text] -> [Maybe Text] -> IO ()
cb n cnl ct = do print $ cnl !! 1
return ()
to
cb :: ExecCallback
cb n cnl ct = do print $ cnl !! 1
return ()
and everything would still work as is. It can make your code shorter and more readable.
One other good example is
type String = [Char]
in Prelude. I bet you normally use String instead of [Char] in most cases. But you're absolutely free to use either.
Another (completely unrelated) example is the conduit package where some type synonyms make a major difference:
type Sink i = ConduitM i Void
type Consumer i m r = forall o. ConduitM i o m r
For something that's a sink for values of any type i, Sink i seems way more readable than ConduitM i Void. Same for Consumer.
I'm trying to write code that will prompt the user to enter a Float and will continue to do so until a valid float is entered.
I've tried the following approach:
getFloat :: Float
getFloat = do
input <- getLine
case (readMaybe input :: Maybe Float) of Just f -> f
Nothing -> do getFloat
But I'm getting the following error:
Main.hs:41:5:
Couldn't match type `IO b0' with `Float'
Expected type: IO String -> (String -> IO b0) -> Float
Actual type: IO String -> (String -> IO b0) -> IO b0
In a stmt of a 'do' block: input <- getLine
In the expression:
do { input <- getLine;
case (readMaybe input :: Maybe Float) of {
Just f -> f
Nothing -> do { ... } } }
In an equation for `getFloat':
getFloat
= do { input <- getLine;
case (readMaybe input :: Maybe Float) of {
Just f -> f
Nothing -> ... } }
Main.hs:42:56:
Couldn't match expected type `IO b0' with actual type `Float'
In the expression: f
In a case alternative: Just f -> f
Main.hs:43:60:
Couldn't match expected type `IO b0' with actual type `Float'
In a stmt of a 'do' block: getFloat
In the expression: do { getFloat }
I'm a beginner a would very much appreciate if someone could explain what am I missing here.
For the Just case, use -> return f instead of -> f.
And then just remove the type signature for getFloat. After it compiles, have ghci tell you what the type signature for getFloat is.
Complete code:
getFloat = do
input <- getLine
case (readMaybe input :: Maybe Float) of Just f -> return f
Nothing -> do getFloat
Update
You might be interested in this highly-polymorphic version of the loop:
{-# LANGUAGE NoMonomorphismRestriction #-}
import Text.Read
getItem = do
input <- getLine
case readMaybe input of
Nothing -> getItem
Just x -> return x
I have purposely written getItem without a type signature - this is something that GHC can infer and fill in for you. I've also used the NoMonomorphismRestriction pragma so that getItem remains polymorphic.
The idea is that getItem can be used for any type that can be read - Floats, Doubles, Strings, etc. The type used by readMaybe can be controlled by the caller in various ways. Here are some examples:
main = do
f1 <- getItem
f2 <- getItem
let r = f1 + f2 :: Float
print r
By forcing r to be type Float, f1 and f2 must also be Floats, and therefore getItem will try to parse a Float.
Here is another way to influence the type that readMaybe uses:
main = do
f <- getItem :: IO Float
i <- getItem :: IO Int
print $ f^i -- compute f raised to the i-th power
getFloat :: Float
This states that getFloat is a constant of type Float, which is not what you want.
getFloat :: IO Float
This instead states that getFloat is an IO action producing a Float.
Once this is fixed, then you need to add return in front of your f, as #ErikR already explained. The return turns the pure float value f into an IO action which produces it, without actually performing any IO.
Finally, you do not need the do in the last do getFLoat. The do syntax is useful to sequence IO actions: if you only have one, it is redundant.