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?
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");
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.
Related
While going through the examples of the Yesod Book, I'm running into an issue with the following snippet:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE ViewPatterns #-}
import Data.Text (Text)
import qualified Data.Text as T
import Yesod
data App = App
instance Yesod App
mkYesod "App" [parseRoutes|
/person/#Text PersonR GET
/year/#Integer/month/#Text/day/#Int DateR
/wiki/*Texts WikiR GET
|]
getPersonR :: Text -> Handler Html
getPersonR name = defaultLayout [whamlet|<h1>Hello #{name}!|]
handleDateR :: Integer -> Text -> Int -> Handler Text -- text/plain
handleDateR year month day =
return $
T.concat [month, " ", T.pack $ show day, ", ", T.pack $ show year]
getWikiR :: [Text] -> Handler Text
getWikiR = return . T.unwords
main :: IO ()
main = warp 3000 App
(It's on page 124 of 598; route arguments)
The instance declaration on line 11 raises the following error:
YesodRouteParams.hs:11:10: error:
• No instance for (RenderRoute App)
arising from the superclasses of an instance declaration
• In the instance declaration for ‘Yesod App’
|
11 | instance Yesod App
|
It can be fixed by moving that line below the mkYesod block, where routes are defined.
I'm trying to understand why that is. Does it mean that Template Haskell evaluation at compile time happens simultaneously with the written code evaluation?
I ask because in Crystal, for example, macros are expanded before anything else. So the order of things doesn't really matter in a file (or app). But by the looks of it, they do in Haskell. Or is there another explanation?
This was because of a change made in GHC 9.0.1. From the release notes:
Breaking change: Template Haskell splices now act as separation points between constraint solving passes. It is no longer possible to use an instance of a class before a splice and define that instance after a splice. For example, this code now reports a missing instance for C Bool:
class C a where foo :: a
bar :: Bool
bar = foo
$(return [])
instance C Bool where foo = True
If you were to downgrade to GHC 8.10.7, you'd see that your code would then work as you wrote it.
I opened https://github.com/yesodweb/yesodweb.com-content/pull/269 to fix the examples in the book.
I'm trying to rewrite a BIG yaml configuration file used in Haksell applicationusing dhall.
To do so I'm using json-to-dhall which requires a SCHEMA which is the type of the resuting expression. The problem is the actual schema is almost impossible to write manually as involves lots of sum types (and nested sum types). I tried to generate the schema by converting manually some parts of the yaml to dhall, and run dhall type. This give a schema that I can use with jston-to-dhall later. This works for simple types, but now I'm facing the problem with unions (of unions). Dhall needs type annotations to write the file I'm using to generate the type ... So I was wondering is there a way (either using a tool or modifying my haskell application) to either dump an Haskell data to a correct dhall file or at least generate the schema from the Haskell type.
Yes, you can generate the Dhall type from the Haskell type.
Here is an example of how to do so:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE TypeApplications #-}
import Data.Either.Validation (Validation(..))
import Data.Text (Text)
import Dhall (FromDhall)
import GHC.Generics (Generic)
import Numeric.Natural (Natural)
import qualified Data.Text.IO as Text.IO
import qualified Dhall
import qualified Dhall.Core
data Mood = Happy | Sad
deriving (Generic, FromDhall)
data Person = Person { age :: Natural, name :: Text, mood :: Mood }
deriving (Generic, FromDhall)
main :: IO ()
main = do
case Dhall.expected (Dhall.auto #Person) of
Success result -> Text.IO.putStrLn (Dhall.Core.pretty result)
Failure errors -> print errors
... which outputs:
$ runghc ./example.hs
{ age : Natural, name : Text, mood : < Happy | Sad > }
I am fairly new to Haskell and have been experimenting with yesod for about a week now. I have been trying to connect to an existing database that has a composite primary key in sqlite. I managed to get the code to work with Database.Persist.Sqlite as a standalone application.
Here is the code that works as a standalone application using persistent-sqlite.
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DeriveGeneric #-}
import Control.Monad.IO.Class (liftIO)
import Database.Persist
import Database.Persist.Sqlite
import Database.Persist.TH
import System.Environment
import Data.Text (Text,pack)
import Data.Time (UTCTime)
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Movie
title Text maxlen=20
year Int maxlen=11
genre Text Maybe maxlen=128
mpaa Text Maybe maxlen=16
director Text Maybe maxlen=128
actors Text Maybe maxlen=512
description Text Maybe maxlen=512
path Text Maybe maxlen=128
codec Text Maybe maxlen=32
length Int Maybe maxlen=11
poster Text Maybe maxlen=128
added UTCTime default=CURRENT_TIMESTAMP
Primary title year
deriving Show
|]
main :: IO ()
main = do
(path:args) <- getArgs
movies <- runSqlite (pack path) $ do
runMigration migrateAll
selectList [] [Desc MovieTitle]
mapM_ print movies
This is sort of a contrived example, but it illustrates my point. I would like to have a composite primary key that consists of title and year. Everything compiles fine and the table is created with the schema that I need. When I try to use the Movie type as defined above in my yesod application with persistent-sqlite, I get the following compile-time error
Foundation.hs:35:1:
No instance for (PathPiece MovieId)
arising from a use of ‘toPathPiece’
In the first argument of ‘(:)’, namely ‘(toPathPiece dyn_apvA)’
In the second argument of ‘(:)’, namely
‘((toPathPiece dyn_apvA) : [])’
In the expression:
((Data.Text.pack "entry") : ((toPathPiece dyn_apvA) : []))
Foundation.hs:35:1:
No instance for (PathPiece MovieId)
arising from a use of ‘fromPathPiece’
In the expression: fromPathPiece
In the pattern: fromPathPiece -> Just dyn_apwt
In the pattern: (:) (fromPathPiece -> Just dyn_apwt) []
I am stuck at this point and unable to continue on my own. I have tried searching, but I am only able to find a working example of composite primary keys without the use of yesod. I have a feeling that it should be possible to do since the composite primary key using only persistent-sqlite works.
Here is how the Movie type is defined in config/models
Movie
title Text maxlen=20
year Int maxlen=11
genre Text Maybe maxlen=128
mpaa Text Maybe maxlen=16
director Text Maybe maxlen=128
actors Text Maybe maxlen=512
description Text Maybe maxlen=512
path Text Maybe maxlen=128
codec Text Maybe maxlen=32
length Int Maybe maxlen=11
poster Text Maybe maxlen=128
added UTCTime default=CURRENT_TIMESTAMP
Primary title year
deriving
I haven't actually used the composite primary key feature myself, but this error makes sense to me. There's not obvious serialization to Text for arbitrary composite keys, and so persistent doesn't generate it for you. If you'd like to use a MovieId inside your URLs, you'll need to manually define the PathPiece instance, which is just a pair of functions for converting to and from Text.
I'm just learning Yesod/Haskell.
In the following code (http://www.yesodweb.com/book/restful-content) there are two things I don't understand (and a subsequent question).
{..} - what does that mean? (It's a hard term to google for.)
person#Person - what does the # sign do?
Is there a way I can find answers to ungooglable Haskell syntax, without bothering you all on StackOverflow?
code:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
import Data.Text (Text)
import Yesod
data Person = Person
{ name :: Text
, age :: Int
}
instance ToJSON Person where
toJSON Person {..} = object
[ "name" .= name
, "age" .= age
]
data App = App
mkYesod "App" [parseRoutes|
/ HomeR GET
|]
instance Yesod App
getHomeR :: Handler TypedContent
getHomeR = selectRep $ do
provideRep $ return
[shamlet|
<p>Hello, my name is #{name} and I am #{age} years old.
|]
provideJson person
where
person#Person {..} = Person "Michael" 28
main :: IO ()
main = warp 3000 App
For points 1 and 2, I guess you're referring to line
person#Person {..}
The {..} comes from the RecordWildcards extension. Basically it brings in scope all fields of the Person datatype. That's why you can use name and age in the Hamlet template above.
The # serves as an alias. Everytime you see id#deconstructor_expr you can use id for the entire value which is deconstructed by deconstructor_expr. For example you can have
f (x:a#(y:_)) = a
and a will be the tail of the argument list as long as the list has at least 2 elements (that is f is tail for lists with more than 2 elements).
Without these two, the entire function would have to change to
getHomeR :: Handler TypedContent
getHomeR = selectRep $ do
provideRep $ return
[shamlet|
<p>Hello, my name is #{name'} and I am #{age'} years old.
|]
provideJson person
where
person = Person "Michael" 28
name' = name person
age' = age person
Observe that name and age are functions from the record to the specific field and that means that you have to use other names for the values (the '-ending variables). Also, because we no longer use # we need separate lines for the person and for the fields.
Another alternative would be
getHomeR :: Handler TypedContent
getHomeR = selectRep $ do
provideRep $ return
[shamlet|
<p>Hello, my name is #{name person} and I am #{age person} years old.
|]
provideJson person
where
person = Person "Michael" 28
You still need to call the name and age functions.
For point 3, a possibility is to go on IRC on #haskell and ask there. Anyway, the same people from there are here, it's not a bother in asking.
Adding to other answers, for searching for ungooglable syntax use symbolhound.com.
{..} unpacks a record into variables. In your case it defines name and age. # takes the entire value in a pattern match, so in person#Person {..}, person would be the original Person value.
Intro:
While checking out snoyman's "persistent" library I found myself wanting ghci's (or another tool) assistance in figuring out stuff.
ghci's :info doesn't seem to work as nicely with type-families and data-families as it does with "plain" types:
> :info Maybe
data Maybe a = Nothing | Just a -- Defined in Data.Maybe
...
> :info Persist.Key Potato -- "Key Potato" defined in example below
data family Persist.Key val -- Defined in Database.Persist
... (no info on the structure/identity of the actual instance)
One can always look for the instance in the source code, but sometimes it could be hard to find it and it may be hidden in template-haskell generated code etc.
Code example:
{-# LANGUAGE FlexibleInstances, GeneralizedNewtypeDeriving, MultiParamTypeClasses, TypeFamilies, QuasiQuotes #-}
import qualified Database.Persist as Persist
import Database.Persist.Sqlite as PSqlite
PSqlite.persistSqlite [$persist|
Potato
name String
isTasty Bool
luckyNumber Int
UniqueId name
|]
What's going on in the code example above is that Template-Haskell is generating code for us here. All the extensions above except for QuasiQuotes are required because the generated code uses them.
I found out what Persist.Key Potato is by doing:
-- test.hs:
test = PSqlite.persistSqlite [$persist|
...
-- ghci:
> :l test.hs
> import Language.Haskell.TH
> import Data.List
> runQ test >>= putStrLn . unlines . filter (isInfixOf "Key Potato") . lines . pprint
where newtype Database.Persist.Key Potato = PotatoId Int64
type PotatoId = Database.Persist.Key Potato
Question:
Is there an easier way to get information on instances of type families and data families, using ghci or any other tool?
Does -ddump-splices show you the TH-generated code in this case?
Otherwise, :browse does give you info about data family instances, though not about type families.
You might want to file a ghc ticket - the :browse output looks mangled, and one might expect data family instances to be reported like class instances, by :info.