Skip to content

Latest commit

 

History

History
78 lines (55 loc) · 2.31 KB

How-to-implement-a-foreign-function-with-a-constraint.md

File metadata and controls

78 lines (55 loc) · 2.31 KB

Implementing the constraint

Suppose that you wish to have a safe foreign function that can only be used with instances of a given typeclass. For example:

moduleComputerToolswhereclassComputerfwherecompute::f->Intforeignimporttriplicate::forallc. (Computerc) =>c->Int

Though triplicate takes only one argument in PureScript side, its definition in foreign side needs one more: a Computer type-class dictionary (PureScript by Example 10.9)

// module ComputerTools exports.triplicate=function(aComputerDictionary){returnfunction(aComputerInstance){return3*aComputerDictionary.compute(aComputerInstance);};};

Alternative

If you don't like relying on the runtime representation of type class dictionaries there is another option: you just should pass in the functions explicitly. Then you’d define a wrapper that actually takes the constraint. So instead of

foreignimporttriplicate::forallc. (Computerc) =>c->Int

you would do

-- This function is unsafe:-- c should be a Computer instance-- but the type checker can't verify thisforeignimporttriplicateImpl::foralla. (a->Int) ->a->Int-- now triplicate is not foreigntriplicate::forallc. (Computerc) =>c->Int triplicate = triplicateImpl compute

and then you’d have a non-foreign wrapper, that actually has the constraint, and you’d just pass in compute to the foreign function.

But now someone could use the unsafe triplicateImpl. There is a trivial solution for that problem: you don’t export the foreign function, you only export your wrapper that takes the constraint.

moduleComputerTools ( Computer , compute , triplicate ) whereclassComputerfwherecompute::f->IntforeignimporttriplicateImpl::foralla. (a->Int) ->a->Inttriplicate::forallc. (Computerc) =>c->Int triplicate = triplicateImpl compute
// module ComputerTools exports.triplicateImpl=function(shouldBeComputeFunction){returnfunction(shouldBeComputerInstance){return3*shouldBeComputeFunction(shouldBeComputerInstance);};};
close