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 runEffectFn
s.
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:
- adding an annotation to the
error
field in the final returned record
- 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).