haskell-beam / haskell-beam/beam

Inference problems with insertions

Open
#243 4 comments 1 reaction 0 assignees View on GitHub
Dominant language
Haskell
Stars
635
Forks
193
PR merge metrics
No merged PRs in 30d

Description

Hi,

I'm in the process of trying out this library. After a gruelling day and a half spent wrangling my ten tables into beam-migrate and trying to figure out beam-migrate-cli (and staying with autoMigrate in the end), I'm finally in trying to write my first query. I'm translating the core of another application that uses Persistent - what drove me to try this out is the support for mixins, which I'm trying to use to the fullest.

Anyway, the query I'm trying to build is just a simple text fixture for inserting users:
```
addUsers :: Pg ()
addUsers = do
now <- zonedTimeToLocalTime <$> liftIO getZonedTime
users <- forM ["admin", "user"] $ \u -> do
hash <- liftIO $ T.pack . BS.unpack <$> makePassword (BS.pack $ T.unpack u) 17
return $ User default_ (val_ u) (just_ $ val_ hash) (val_ True) (emptyBlamable Nothing)
runInsert . insert (user starletDb) $ insertExpressions users
```
The problem I have is with the `s` (scope?) that `insertExpressions` is forall'd over and the GHC tells me that it `Couldn't match type ‘s’ with ‘s'’ because type variable ‘s'’ would escape its scope`.

Trying to explicitly annotate `users :: [forall s. UserT (QExpr PgExpressionSyntax s)] <- ...` causes the compiler to give up with the error `llegal polymorphic type: forall s. QExpr syntax s. GHC doesn't yet support impredicative polymorphism`.

The only (ugly) solution I can think of is to use a newtype to hide the `s` parameter, though I'm not sure that'd work the way I expect it to.

I did manage to make the query work by moving the `User` construction inside `insertExpressions`:
```
addUsers :: Pg ()
addUsers = do
now <- zonedTimeToLocalTime <$> liftIO getZonedTime
users <- forM ["admin", "user"] $ \u -> do
hash <- liftIO $ T.pack . BS.unpack <$> makePassword (BS.pack $ T.unpack u) 17
return (u, hash)
runInsert . insert (user starletDb) $ insertExpressions $ flip fmap users $ \(u, p) ->
User default_ (val_ u) (just_ $ val_ p) (val_ "") (val_ True) (emptyBlamable Nothing)
```
That solves this particular problem, but I'd like to know how to do it with the first construction (if it's possible to convince the compiler...).

Also, I've stumbled upon another inference-related problem - replacing `runInsert $ insert (user starletDb) $ insertExpressions $ flip fmap users $ ...` by the nicer point-free version `runInsert . insert (user starletDb) . insertExpressions . flip fmap users $ ...` causes the compiler to want to infer `[UserT (QExpr syntax s)]` with a unified `s` - whereas the immediately applied version keeps the `forall s.`.

I'm sure there is an easy solution to both of these, but while I've played with TypeFamilies et al. quite a bit, I haven't really used this type of nested `forall`s yet, so I'm reduced to having a one-sided conversation with GHC :)

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.