deriving Generic doesn't work even though DeriveGeneric is on - haskell

I'm trying to follow the tutorial for the Beam Haskell library: https://tathougies.github.io/beam/tutorials/tutorial1/
module Lib
( someFunc
) where
{-# LANGUAGE
DeriveGeneric
, GADTs
, OverloadedStrings
, FlexibleContexts
, FlexibleInstances
, TypeFamilies
, TypeApplications
#-}
import Database.Beam
import Database.Beam.Postgres
import GHC.Generics
import Data.Text (Text)
data UserT f
= User
{ _userEmail :: Columnar f Text
, _userFirstName :: Columnar f Text
, _userLastName :: Columnar f Text
, _userPassword :: Columnar f Text }
deriving Generic
someFunc :: IO ()
someFunc = putStrLn "someFunc"
This results in the following error:
• Can't make a derived instance of ‘Generic (UserT f)’:
You need DeriveGeneric to derive an instance for this class
• In the data declaration for ‘UserT’
|
27 | deriving Generic
| ^^^^^^^
Note that the DeriveGeneric language pragma is present.
What am I missing here?
Build environment:
stack lts-11.9
Linux

A {-# LANGUAGE #-} declaration needs to go at the very top of the file, before the module declaration.

Related

DuplicateRecordFields causes Template Haskell 'Illegal variable name' error

I do not understand why the DuplicateRecordFields language pragma is causing a compile time error in a template haskell splice.
Example:
-- TypeModule.hs
{-# LANGUAGE DuplicateRecordFields #-}
module TypeModule where
data A = A {foo :: Int} deriving Show
-- ThModule.hs
{-# LANGUAGE TemplateHaskell #-}
module ThModule where
import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import TypeModule
mkLambda :: Q [Dec]
mkLambda = [d| func :: A -> Int; func = foo |]
-- Lib.hs
module Lib where
import TypeModule
import ThModule
$mkLambda
{-
Illegal variable name: ‘$sel:foo:A’
When splicing a TH declaration: func_0 = (TypeModule.$sel:foo:A)
|
8 | $mkLambda
| ^^^^^^^^
-}
When I remove the DuplicateRecordFields pragma, the compile time error goes away.
I am using the DuplicateRecordFields pragma because I am parsing a number of different JSON objects which are responses from a REST API, and many of these JSON objects contain fields with identical names.
Right now I am looking for a way that does not use DuplicateRecordFields, but at the least I would like to understand what in particular is causing the compiler trouble.
This seems to be a known GHC issue: https://gitlab.haskell.org/ghc/ghc/-/issues/14848

Scotty and persistence - type error when using insert function

I've got the following application:
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module Main where
-- Scotty
import qualified Web.Scotty as S
import Network.Wai.Middleware.RequestLogger
import Network.Wai.Middleware.Static
import qualified Data.Text.Lazy as L
-- HTML rendering
import Text.Blaze.Html.Renderer.Text (renderHtml)
import qualified Text.Blaze.Html5 as H
import qualified Text.Blaze.Html5.Attributes as A
import Control.Monad.IO.Class
-- Database
import Database.Persist
import Database.Persist.Sqlite
import Database.Persist.TH
import Control.Monad.Trans.Resource (runResourceT, ResourceT)
import Control.Monad.Logger
-- URL generation
import System.Random
import Control.Monad (replicateM)
-- JSON
import Data.Map (fromList)
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Link
shortUrl L.Text
URLKey shortUrl
Primary shortUrl
longUrl L.Text
counter Int
deriving Show
|]
getURL :: L.Text -> IO (Maybe (Entity Link))
getURL shortId = runSqlite "links.db" $ do
maybeOriginal <- getBy $ URLKey shortId
pure maybeOriginal
-- I don't know what type to give this, that's probably the problem
addURL short long = runSqlite "links.db" $ do
insert $ Link short long
main :: IO ()
main = do
-- Connect to db and run migration
runSqlite "links.db" $ do runMigration migrateAll
S.scotty 3000 $ do
...
S.post "/shorten" $ do
-- Get URL
url <- S.param "url" :: S.ActionM L.Text
-- Generate a random short URL
randStr <- liftIO $ getRandStr 5
-- Add the urls to the database
liftIO $ addURL (L.pack randStr) url
-- Send JSON response with ID
S.json $ fromList [("id" :: String, randStr)]
I get the following error:
shortener> build (lib + exe)
Preprocessing library for shortener-0.1.0.0..
Building library for shortener-0.1.0.0..
Preprocessing executable 'shortener-exe' for shortener-0.1.0.0..
Building executable 'shortener-exe' for shortener-0.1.0.0..
[2 of 2] Compiling Main
/home/henry/haskell/shortener/app/Main.hs:86:5: error:
• Couldn't match type ‘PersistEntityBackend (Int -> Link)’
with ‘SqlBackend’
arising from a use of ‘insert’
• In the first argument of ‘($)’, namely ‘insert’
In a stmt of a 'do' block: insert $ Link short long
In the second argument of ‘($)’, namely
‘do insert $ Link short long’
|
86 | insert $ Link short long
| ^^^^^^
-- While building package shortener-0.1.0.0 (scroll up to its section to see the error) using:
/home/henry/.stack/setup-exe-cache/x86_64-linux-tinfo6/Cabal-simple_mPHDZzAJ_3.4.1.0_ghc-9.0.2 --builddir=.stack-work/dist/x86_64-linux-tinfo6/Cabal-3.4.1.0 build lib:shortener exe:shortener-exe --ghc-options " -fdiagnostics-color=always"
Process exited with code: ExitFailure 1
I'm not sure how to resolve this type error and I haven't been able to find anything of use online. There was this answer with a similar problem, but the given type signature and several variations of it did not work.
It turns out I forgot a field when inserting. I had
insert $ Link short long
I needed
insert $ Link short long 0
for the counter field of Link.
Unfortunately the error didn't make that at all clear.

Haskell RIO monad inside persistent with pool

Similar question: Haskell / Persistent-Sqlite: "No instance for (Control.Monad.Trans.Resource.MonadResource IO)"
I'm trying the use the selectSource from persistent to read the database in streaming mode and log the values in the console using logInfo.
The following snippets are executed in a RIO project template.
The following code contains the parts that work and don't work.
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
module Disambiguate.People where
import Data.Conduit
import qualified Data.Conduit.List as CL
import Database.Persist
import Database.Persist.Sqlite
import Database.Persist.TH
import Import hiding (on, (^.))
import Prelude (print)
share [mkPersist sqlSettings, mkMigrate "migrateAll"] [persistLowerCase|
Person
name String
age Int
deriving Show
|]
disambiguatePeople :: RIO App ()
disambiguatePeople = do
-- WORKS!
runSqlite ":memory:" insertAndRead
-- DOES NOT COMPILE!
withSqlitePool ":memory:" 1 $ \pool -> do
liftSqlPersistMPool insertAndRead pool
where
insertAndRead = do
runMigration migrateAll
insert_ $ Person "John Doe" 35
insert_ $ Person "Jane Doe" 50
runConduit $ selectSource [PersonAge >. 5] [] .| CL.mapM_
(lift . logInfo . displayShow)
I get the following error:
src/Run.hs:37:25: error:
• Couldn't match type ‘RIO App’ with ‘IO’
Expected type: ReaderT
SqlBackend
(monad-logger-0.3.35:Control.Monad.Logger.NoLoggingT
(Control.Monad.Trans.Resource.Internal.ResourceT IO))
()
Actual type: ReaderT
SqlBackend
(monad-logger-0.3.35:Control.Monad.Logger.NoLoggingT
(Control.Monad.Trans.Resource.Internal.ResourceT (RIO App)))
()
• In the first argument of ‘liftSqlPersistMPool’, namely
‘insertAndRead’
In a stmt of a 'do' block: liftSqlPersistMPool insertAndRead pool
In the expression: do liftSqlPersistMPool insertAndRead pool
|
37 | liftSqlPersistMPool insertAndRead pool
| ^^^^^^^^^^^^^
I understand the error since the function liftSqlPersistMPool hardcoded the IO type.
How can I solve this to use it with the RIO type ?

By what mechanism does Generic interact with Aeson's ToJSON class?

Looking at part of the servant example, I see:
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
module Main where
import Prelude ()
import Prelude.Compat
import Control.Monad.Except
import Control.Monad.Reader
import Data.Aeson.Types
import Data.Attoparsec.ByteString
import Data.ByteString (ByteString)
import Data.List
import Data.Maybe
import Data.String.Conversions
import Data.Time.Calendar
import GHC.Generics
import Lucid
import Network.HTTP.Media ((//), (/:))
import Network.Wai
import Network.Wai.Handler.Warp
import Servant
import System.Directory
import Text.Blaze
import Text.Blaze.Html.Renderer.Utf8
import qualified Data.Aeson.Parser
import qualified Text.Blaze.Html
type UserAPI1 = "users" :> Get '[JSON] [User]
data User = User
{ name :: String
, age :: Int
, email :: String
, registration_date :: Day
} deriving (Eq, Show, Generic)
instance ToJSON User
When I removed the deriving of Generic, I got the following error:
• No instance for (Generic User)
arising from a use of ‘aeson-1.1.2.0:Data.Aeson.Types.ToJSON.$dmtoJSON’
So, it appears that the Generic typeclass instance for User enables instance ToJSON User to, I'm assuming, create a JSON Encoder for User.
What's the machinery of instance ToJSON User, i.e. type signature, if that's the right word?
I'm trying to look at its type from the stack ghci, i.e. REPL, but failing:
λ: >:t instance
<interactive>:1:1: error: parse error on input ‘instance’
λ: >:i instance
<interactive>:1:1: error: parse error on input ‘instance’
Let's look at the source for ToJSON:
class ToJSON a where
-- | Convert a Haskell value to a JSON-friendly intermediate type.
toJSON :: a -> Value
default toJSON :: (Generic a, GToJSON Zero (Rep a)) => a -> Value
toJSON = genericToJSON defaultOptions
The ToJSON class has a default toJSON implementation with additional type constraints (including Generic, as you've noticed). This requires the DefaultSignatures extension; notice at the top of that module you can see
{-# LANGUAGE DefaultSignatures #-}
The other constraint, GToJSON Zero (Rep a), imposes some further restrictions on the structure of a, and so not every type with a Generic instance will satisfy this signature.
Regarding your question about GHCi: instance is a Haskell keyword. Inspecting toJSON may be what you want instead. This will show you the same information we saw in the source:
λ> :i toJSON
class ToJSON a where
toJSON :: a -> Value
default toJSON :: (GHC.Generics.Generic a,
GToJSON Zero (GHC.Generics.Rep a)) =>
a -> Value
...
-- Defined in ‘aeson-1.1.2.0:Data.Aeson.Types.ToJSON’

How do you add a unique key to a Database.Persist model using the quasiquoter?

How do you build a unique key with two or more fields using the persistLowerCase quasiquoter?
When using Database.Persist to create models for a simple website using guidance from the Yesod book, the following error crops up:
Build FAILED
$PREFIX/App/Models.hs: line 42, column 18:
Not in scope: data constructor `GroupSlug'
$PREFIX/App/Models.hs: line 43, column 19:
Not in scope: data constructor `GroupName'
App/Models.hs
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeSynonymInstances #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
module App.Models where
import Data.Text (Text)
import Database.Persist.TH
share [ mkPersist sqlSettings
, mkMigrate "migrateAll"] [persistLowerCase|
Post
group GroupId
postName Text
postSlug Text
period Text
content_en Text
content_pt Text
UniquePost postSlug
deriving Show
Group
groupId Int
groupName Text
groupSlug Text
parent GroupId
UniqueGroup groupId groupSlug
deriving Show
|]
App/Handlers.hs
{-# LANGUAGE OverloadedStrings #-}
module App.Handlers where
import Database.Esqueleto
import App.Models
groupQuery x =
select $
from $ \g -> do
where_ (g ^. GroupSlug ==. val x)
return $ g ^. GroupName
Versions:
Haskell Platform 2013.2
Cabal == 1.19.2
persistent == 1.3.0.2
scotty == 0.6.2
esqueleto == 1.3.4.5
Am I missing some extension or overlooking something else?
As far as I'm aware, data constructors that you're trying to use are actually called GroupGroupSlug and GroupGroupName (not just GroupSlug and GroupName). That is because the data type is generated by taking the entity name and joining it with the field name (with proper capitalisation). Try loading your source files with the -ddump-splices command-line parameter, and you should see it in the output somewhere.

Resources