Reputation: 3980
This is a "hello world" attempt that's currently failing - I am simply trying to run a selectList
query on a SqLite database with the following code:
Database.Persist.Sqlite> runSqlite "database.sqlite" $ selectList [] [LimitTo 10]
<interactive>:46:1:
Couldn't match expected type ‘SqlBackend’
with actual type ‘PersistEntityBackend val0’
The type variable ‘val0’ is ambiguous
In the first argument of ‘print’, namely ‘it’
In a stmt of an interactive GHCi command: print it
This almost seems too simple to screw-up... where did I go wrong?
Upvotes: 4
Views: 728
Reputation: 9364
For posterity: I recently struggled with The type variable ‘backend0’ is ambiguous
for a toy Sqlite example. The complier (rightly) couldn't figure out which backend
I wanted to use for which BaseBackend backend = SqlBackend
.
Turns out there are three of these: SqlBackend
, SqlWriteBacknde
and SqlReadBackend
. Yes, for the first one, the resolved associated type happens to resolve to itself, if you wonder if it's a typo.
You can either fix by putting an explicit type signature somewhere (stick a type hole :: _
on an operation to get a hint), or by including the runMigration
call in your operations, which magically fixes the type variable to SqlBackend
.
Upvotes: 3
Reputation: 12070
As you probably already know, one of Haskell's strengths is strong typing. The persistent-sqlite package takes this to an extreme (which, in my opinion, is a good thing) by requiring that table entries have their own data type.
For instance, if you have a table which holds fruits that looks like this
_______________________
|Fruit ID | Fruit Name|
-----------------------
| 0 | "apple" |
| 1 | "orange" |
-----------------------
and you do a query against this table using persistent-sqlite, the results should be stored in a corresponding Fruit type
data Fruit = Fruit { fruitName::String }
Just creating said data type isn't enough, there is a bunch of boilerplate code to create the needed class instances to actually use this. Rather than create this all by hand, you can use the template Haskell magic in the persistent-template library to create all of this for you.
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Fruit
name String
deriving Show
|]
Your example code was actually correct, but was missing all of this stuff. Furthermore, the compiler didn't even know what type to try to use, so, the error message you got contained the following sentence
The type variable ‘val0’ is ambiguous
which was basically the compilers way of saying, "I don't know what type to extract the sql entry to." You can specify with an explicit type
print (fruits :: [Entity Fruit])
Finally, unfortunately, this code uses a bunch of GHC extensions. Putting this together, here is a more complete working simplest example.
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
import Control.Monad.IO.Class (liftIO)
import Database.Persist.Sqlite
import Database.Persist.TH
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Fruit
name String
deriving Show
|]
main :: IO ()
main = runSqlite "fruitDb.sqlite" $ do
fruits <- selectList [] [LimitTo 10]
liftIO $ print (fruits :: [Entity Fruit])
and just to be complete, here is how to populate the sqlite db to test this.
> sqlite3 fruitDb.sqlite
sqlite> create table fruit (id, name);
sqlite> insert into fruit values (0, "apple");
sqlite> insert into fruit values (1, "orange");
Upvotes: 6