Error: Could not match constrained type

Hi,

I’m having difficulty with the following code:

class Any :: forall k. k -> Constraint
class Any a
instance Any String
instance Any Int
instance Any Number
instance Any Object

type LogFunctionFFI = forall a. Any a => EffectFn1 (Array a) (Effect Unit)
type LogFunction = forall a. Any a => Array a -> Effect Unit

type LogFunctions f =
        { | ( error :: f) }
--         -- , warn :: f
--         -- , info :: f
--         -- , verbose :: f
--         -- , debug :: f
--         -- , silly :: f
--         -- , log :: f
--         | r
--         )

foreign import _logImpl :: Effect (LogFunctions LogFunctionFFI)

electronLog :: Effect (LogFunctions LogFunction)
electronLog = do
    _log <- _logImpl
    let logIntf :: LogFunctionFFI -> LogFunction
        logIntf f = \params -> join $ runEffectFn1 f params
        error = logIntf _log.error -- <-- error is here
        -- warn = logIntf _log.warn
        -- info = logIntf _log.info
        -- verbose = logIntf _log.verbose
        -- debug = logIntf _log.debug
        -- silly = logIntf _log.silly
        -- log = logIntf _log.log
    pure { error } -- , warn, info, verbose, debug, silly, log }

Getting this error:

   Could not match constrained type

    Any t2 => EffectFn1 (Array t2) (Effect Unit)

  with type

    EffectFn1 (Array a0) (Effect Unit)

while trying to match type Any @Type t2 => EffectFn1 (Array t2) (Effect Unit)
  with type EffectFn1 (Array a0) (Effect Unit)
while checking that expression _log
  has type { error :: EffectFn1 (Array a0) (Effect Unit)
           | t1
           }
while checking type of property accessor _log.error
in value declaration electronLog
where a0 is a rigid type variable
        bound at (line 40, column 25 - line 40, column 35)
      t1 is an unknown type
      t2 is an unknown type

What am I doing wrong? I just want to create interface structure between the javascript and purescript side eliminating runEffectFns.

Thanks in advance.

This code compiles. I’m not sure if that’s what you’re looking for though:

class Any :: forall k. k -> Constraint
class Any a
instance Any String
instance Any Int
instance Any Number

type LogFunctionFFI a = EffectFn1 (Array a) (Effect Unit)
type LogFunction a = Array a -> Effect Unit

type LogFunctions f =
        { | ( error :: f) }

foreign import _logImpl :: forall a. Effect (LogFunctions (LogFunctionFFI a))

electronLog :: forall a. Any a => Effect (LogFunctions (LogFunction a))
electronLog = do
    _log <- _logImpl
    let logIntf :: LogFunctionFFI a -> LogFunction a
        logIntf f = \params -> join $ runEffectFn1 f params
        
        error :: LogFunction a
        error = logIntf _log.error
    pure { error }

I’m able to get it working by:

  1. adding an annotation to the error field in the final returned record
  2. switching the FFI function to take an Array Foreign instead of forall a. Any a => Array a

FFI with constraints gets a little weird, as the constraint becomes an additional real function argument under the hood, and that parameter just gets supplied automatically by the compiler in normal PureScript code. See these docs on constrained types in FFI. Since you’re not exposing your _logImpl outside of this module, IMO it’s better to just use Foreign to keep the FFI simple while exposing your forall a. Any a => Array a in your public type so you still get the type safety.
I’m not sure I can really say why the annotation on the record is necessary though.

class Any :: forall k. k -> Constraint
class Any a
instance Any String
instance Any Int
instance Any Number
instance Any Object

type LogFunctionFFI = EffectFn1 (Array Foreign) (Effect Unit)
type LogFunction = forall a. Any a => Array a -> Effect Unit

type LogFunctions f = { error :: f }

foreign import _logImpl :: Effect (LogFunctions LogFunctionFFI)

logIntf :: LogFunctionFFI -> LogFunction
logIntf f = \params -> join $ runEffectFn1 f (unsafeToForeign <$> params)

electronLog :: Effect (LogFunctions LogFunction)
electronLog = do
    _log <- _logImpl
    let error = logIntf _log.error 
    pure { error: (error :: forall a. Any a => Array a -> Effect Unit) } 

@JordanMartinez and @ntwilson, thank you for your replies.

I think I should go to a easier path. I’ve just stripped off Any class and replaced Array a with String for now. May be later I can implement polymorphic interface (probably not because I realized that Data.Interpolate.i function is much better interface).