haskellhaskell-polysemy

polysemy does not detect a member


I am trying to write a bunch of statements with Hspec inside a single polysemy's Sem Monad as such:

{-# OPTIONS_GHC -fplugin=Polysemy.Plugin #-}

{-# LANGUAGE DataKinds           #-}
{-# LANGUAGE FlexibleContexts    #-}
{-# LANGUAGE GADTs               #-}
{-# LANGUAGE KindSignatures      #-}
{-# LANGUAGE LambdaCase          #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE RankNTypes          #-}
{-# LANGUAGE TemplateHaskell     #-}
{-# LANGUAGE TypeApplications    #-}
{-# LANGUAGE TypeOperators       #-}

module StorageSpec (main, spec) where

import Test.Hspec

import Storage
import Data.Aeson
import Data.Maybe(fromJust)
import qualified Data.Text as T
import qualified Database.Bloodhound as B
import qualified Database.Bloodhound.Types as B
import GHC.Generics
import Polysemy (Embed, Member, Sem, makeSem, embed, interpret, reinterpret)
import Polysemy.IO
import Polysemy.State


data Storage (d :: *) (m :: * -> *) (a :: *) where
  CreateContainer :: B.IndexName -> B.IndexSettings -> Storage d m Bool

makeSem ''Storage

scenarii :: Member (Storage Book) r => Sem r (SpecWith ())
scenarii = do
  indexCreation <- it "create index should work the first time" . flip shouldBe True
    <$> (createContainer exampleIndex exampleMapping :: Member (Storage Book) r => Sem r Bool)
  return $ indexCreation

data Book = Book { name :: String, entries :: Int } deriving (Eq, Show, Generic, FromJSON, ToJSON)

While specifying explicitly the Storage Book Member I have the following error:

    • Ambiguous use of effect 'Storage'
      Possible fix:
        add (Member (Storage d1) r1) to the context of
          the type signature
      If you already have the constraint you want, instead
        add a type application to specify
          'd1' directly, or activate polysemy-plugin which
            can usually infer the type correctly.
    • In the second argument of ‘(<$>)’, namely
        ‘(createContainer exampleIndex exampleMapping ::
            Member (Storage Book) r => Sem r Bool)’
      In a stmt of a 'do' block:
        indexCreation <- it "create index should work the first time"
                           . flip shouldBe True
                           <$>
                             (createContainer exampleIndex exampleMapping ::
                                Member (Storage Book) r => Sem r Bool)
      In the expression:
        do indexCreation <- it "create index should work the first time"
                              . flip shouldBe True
                              <$>
                                (createContainer exampleIndex exampleMapping ::
                                   Member (Storage Book) r => Sem r Bool)
           return $ indexCreation
   |
39 |     <$> (createContainer exampleIndex exampleMapping :: Member (Storage Book) r => Sem r Bool)
   |          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

I do not see what can I do to help the type-checker.


Solution

  • It occurs that d acts as a Phantom type in case of CreateContainer, in order to fix it I had to use type application:

    createContainer @Book exampleIndex exampleMapping