How to use Hakyll.loadSnapshot without "No instance for (Typeable a0)" error - haskell

I'm trying to add some functionality to my site so that I can expose different versions of a post. For example, if my source directory contains
mypost/version/1
mypost/version/2
mypost/version/3
I'd like to copy all of the versions of the post into the generated site, along with a new path mypost/version/latest.
To accomplish this, I compile each version of the post and take a snapshot using saveSnapshot. Then I iterate over everything in the mypost/version directory to find the latest version. Finally, I want to get the compiled snapshot of the latest version and copy it into the mypost/version/latest directory.
In my site generator, I pass the output of loadSnapshot into an item-copying compiler, along the lines of:
loadSnapshotAndCopy :: Snapshot -> Compiler (Item CopyFile)
loadSnapshotAndCopy snapshot = do
identifier <- getUnderlying
item <- loadSnapshot identifier snapshot
provider <- compilerProvider <$> compilerAsk
makeItem $ CopyFile $ resourceFilePath provider (itemIdentifier item)
However, this produces an error:
• No instance for (Typeable a0)
arising from a use of ‘loadSnapshot’
• In a stmt of a 'do' block:
item <- loadSnapshot identifier snapshot
In the expression:
do identifier <- getUnderlying
item <- loadSnapshot identifier snapshot
provider <- compilerProvider <$> compilerAsk
makeItem
$ CopyFile $ resourceFilePath provider (itemIdentifier item)
In an equation for ‘loadSnapshotAndCopy’:
loadSnapshotAndCopy snapshot
= do identifier <- getUnderlying
item <- loadSnapshot identifier snapshot
provider <- compilerProvider <$> compilerAsk
....
|
248 | item <- loadSnapshot identifier snapshot
| ^^^^^^^^^^^^
The type of loadSnapshot is loadSnapshot :: (Binary a, Typeable a) => Identifier -> Snapshot -> Compiler (Item a), so I guess there's a constraint that the compiler is unable to satisfy for some reason. How can get around this in order to use loadSnapshot?

Related

In Yesod.Test, is it possible to get into `SpecM (TestApp site)` from `IO`, similarly to how `liftIO` allows the opposite?

More specifically, I'm looking for a function of type:
f :: site -> SpecM (TestApp site) b -> IO b
or similar.
In other words, I am looking for the inverse function of:
liftIO :: IO b -> SpecM (TestApp _site) b
I've looked in the Yesod.Test docs and source code and tried to construct it myself too, but I don't seem to find it anywhere and it doesn't seem to be simple to construct either. Have I overlooked something, and might it exist somewhere? Or could it be simple to construct in a way I have not considered?
Background
I've run into the need for such a function multiple times, but so far I've always been able to workaround or do without. But in my latest situation it doesn't seem possible to work around: I want to write a Monadic QuickCheck property that would set up an arbitrary db environment (runDB . insert) and run some handlers on it to test for certain invariants of my application.
This is the farthest I've gotten with my attempts:
propSpec = do
context "qt" $ do
it "monadic" $ property $ \a b -> monadicIO $ do
run $ withServer $ \site -> yesodSpec site $ runDB $ insert $ User{..}
assert $ a /= b
withServer cont = do
p <- runLogging $ withSqlitePool "database_test.db3" 10 $ \pool -> do
runSqlPool (runMigration migrateAll) pool
return pool
wipeDB (MyApp p)
cont (MyApp p, id)
Which, somewhat understandably, results in the following type error:
/path/to/project/spec/Spec.hs:301:35: error:
• Couldn't match type ‘hspec-core-2.2.4:Test.Hspec.Core.Spec.Monad.SpecM
() ()’
with ‘IO a0’
Expected type: IO a0
Actual type: Spec
• In the expression:
yesodSpec site $ runDB $ insert $ User{..}
In the second argument of ‘($)’, namely
‘\ site
-> yesodSpec site $ runDB $ insert $ User{..}’
In the second argument of ‘($)’, namely
‘withServer
$ \ site
-> yesodSpec site $ runDB $ insert $ User{..}’
/path/to/project/spec/Spec.hs:301:52: error:
• Couldn't match type ‘ST.StateT
(YesodExampleData MyApp) IO (Key User)’
with ‘transformers-0.5.2.0:Control.Monad.Trans.Writer.Lazy.WriterT
[YesodSpecTree (MyApp, a1 -> a1)]
Data.Functor.Identity.Identity
()’
Expected type: YesodSpec (MyApp, a1 -> a1)
Actual type: YesodExample MyApp (Key User)
• In the second argument of ‘($)’, namely
‘runDB $ insert $ User{..}’
In the expression:
yesodSpec site $ runDB $ insert $ User{..}
In the second argument of ‘($)’, namely
‘\ site
-> yesodSpec site $ runDB $ insert $ User{..}’
• Relevant bindings include
site :: (MyApp, a1 -> a1)
(bound at /path/to/project/spec/Spec.hs:301:27)
Any ideas?
Also, has anyone before used Test.QuickCheck.Monadic successfully in conjunction with Yesod.Test? Or if perhaps not successfully, at least attempted to do so?

Type mismatch in persistent

I am having issues with types matching up in persistent. I have a module called Storage.Mongo like so:
type FieldMap = Map.Map T.Text T.Text
let mongoSettings = (mkPersistSettings (ConT ''MongoBackend)) {mpsGeneric = False}
in share [mkPersist mongoSettings] [persistLowerCase|
Notice
rawData FieldMap
deriving Show
|]
-- | This is the default database pool
defaultPool = createMongoDBPool
"system_of_record"
"localhost"
(PortNumber 33107)
(Just (MongoAuth "reader" "password"))
10
10
30
-- | Save notice to database
saveNotices x = do pool <- defaultPool
runMongoDBPoolDef save pool
where save = mapM_ (insert.Notice) x
I am trying to pass the saveNotices command a field map, which it will convert to a Notice entity and save to a MongoDb database. To wit:
main = do files <- getArgs
mapM_ parseNotice files
where parseNotice f = do x <- parseFromFile fboFile f
case x of
Left err -> print err
Right notices -> mapM_ saveNotices notices
The parseNotice function returns a list of Maps:
notice = do noticeType <- openingTag
fields <- manyTill (try complexField <|> simpleField) (try closingTag)
return $ (Map.fromList(concat ([("NOTICETYPE", noticeType)]:fields)))
fboFile = many notice
I am not sure where the problem is. I believe I should let the compiler the know the type of
mapM_ (insert.Notice) x
is, but I am not sure what the type should be
This is the error I am getting
Couldn't match type 'PersistEntityBackend Notice' with 'MongoBackend' Expected type: PersistEntityBackend Notice Actual type: PersistMonadBackend (Action m) In the first argument of '(.)', namely 'insert' In the first argument of 'mapM_', namely '(insert . Notice)' In the expression: mapM_ (insert . Notice) x
It is failing trying to apply insert . Notice (space added for emphasis)
insert :: MonadIO' m => Collection -> Document -> Action m Value
type Collection = Text
It looks like insert expects a name as its first argument. The following might work.
mapM_ (insert "Notice" $ Notice) x

Resulting Ambiguous Type Variable in Persistent's `get` call

I'm having the following error while trying to retrieve a list of Entities from a list of foreign attributes.
Handler/ContactList.hs:21:57:
Couldn't match type `PersistMonadBackend m0'
with `persistent-1.3.0.6:Database.Persist.Sql.Types.SqlBackend'
The type variable `m0' is ambiguous
Possible fix: add a type sig`enter code here`nature that fixes these type variable(s)
Expected type: PersistEntityBackend User
Actual type: PersistMonadBackend m0
In the expression: `enter code here`get
In the expression: (get $ ((contactContact val) :: UserId))
In the first argument of `map', namely
`(\ (Entity key val) -> (get $ ((contactContact val) :: UserId)))'
The code below gets a List entity which has a one-to-many relationship with contact. In the Contact Model, there is an attribute called contact to represent the foreign key constraint to User (The type for conctact is UserId).
I'm Trying to retrieve the list of contacts (list of userIds) and perform a map get to retrieve the list of user entities.
For my understanding, there is a problem of type generalization while using get on a Contact Entity with UserId type, but I can't figure out what is the proper type it can work with.
getContactsR :: Handler Html
getContactsR = do
muser <- maybeAuth
case muser of
Just (Entity userId user) -> do
(list, contacts) <- runDB $ do
maybeList <- getBy (UniqueList userId)
case maybeList of
Just (Entity listId list) -> do
contacts' <- selectList [ContactList ==. listId] []
let contacts = map (\(Entity key val) -> (get $ ((contactContact val) :: UserId) )) contacts'
return (list, contacts')
Nothing -> error "Could not retrieve contact list"
defaultLayout $(widgetFile "contacts")
Nothing -> do
setMessage $ toHtml ("Error getting contact list" :: Text)
redirect HomeR
Thanks in advance
I think you need to replace:
let contacts = map (\(Entity key val) -> (get $ ((contactContact val) :: UserId) )) contacts'
with:
contacts <- mapM (\(Entity key val) -> (get $ ((contactContact val) :: UserId) )) contacts'
(Yes, the Persistent error messages here are terrible, we're working on that for Persistent 2.0.) I think the UserId type annotation may not even be necessary.

Why am I getting an EitherT type error?

When I try loading my Heist (0.11) templates with this function:
load :: MonadIO n => FilePath -> [(Text, Splice n)] -> IO (HeistState n)
load baseDir splices = do
tmap <- runEitherT $ do
templates <- loadTemplates baseDir
let hc = HeistConfig [] defaultLoadTimeSplices splices [] templates
initHeist hc
either (error . concat) return tmap
I get this error:
Couldn't match expected type `EitherT e0 m0 t0'
with actual type `either-3.1:Control.Monad.Trans.Either.EitherT
[String] IO Heist.TemplateRepo'
In the return type of a call of `loadTemplates'
In a stmt of a 'do' block: templates <- loadTemplates baseDir
In the second argument of `($)', namely
`do { templates <- loadTemplates baseDir;
let hc
= HeistConfig [] defaultLoadTimeSplices splices [] templates;
initHeist hc }'
To me, loadTemplate seems to be returning the expected type, except with the type parameters filled in with concrete types. What am I missing?
This happens in cases where there are multiple versions of the same package installed. Use ghc-pkg to remove all but one version of the either package, then reinstall and try it again.
I've been puzzled by this time and time again. When the types are right and you start to think it's a GHC bug, check for duplicate packages.

Could someone explain to me how I should go about fixing this type signature?

Here's the code, I tried letting type inference figure out the function's type. While the code compiles, it fails at runtime.
Ambiguous type variables `b0', `m0' in the constraint:
(PersistBackend b0 m0) arising from a use of `isFree'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: isFree testDay
In an equation for `it': it = isFree testDay
:t isFree
isFree :: PersistBackend b m => C.Day -> b m Bool
>isFree day = do
match <- selectList [TestStartDate ==. day,
TestStatus !=. Passed,
TestStatus !=. Failed] []
if (L.null match) then (liftIO $ return True) else (liftIO $ return False)
ghci is telling you that it doesn't know which type expressions to choose for b and m. All you have to do is tell it,
isFree testDay :: Foo Bar Bool
In real programmes, these type variables are usually determined at the use site, so you rarely have to specify an expression's type there. At the ghci prompt, the context is missing, so you often have to do it.
Unrelated, the last line of isFree would better be return $ L.null match
"While the code compiles, it fails at runtime." is very unlikely to be an error in supplying a type to this function.
What does "fail" mean?
This is embarrassing. One one hand, this problem did get me to delve into the depths of Yesod monads. One the other hand, this question was already answered for me. When you run a database action, pass the result to runDB like so.
>isFree day = do
match <- runDB $ selectList [TestStartDate ==. day,
TestStatus !=. Passed,
TestStatus !=. Failed] []
if (L.null match) then (liftIO $ return True) else (liftIO $ return False)

Resources