Suppose I have a dumb Frege function that constructs a pair of Num
s.
newPair :: (Num α, Num β) => α -> β -> (α, β)
newPair = (,)
-- alternatively -- newPair x y = (x, y)
Attempting to call this function from Java, however, a PreludeBase.CNum<α>
and a PreludeBase.CNum<β>
are demanded in addition to the expected Lazy<α>
and Lazy<β>
. Likewise with Show
types, where
showSomething :: (Show α) => α -> String
showSomething = show
-- alternatively -- showSomething x = show x
would require a PreludeBase.CShow<α>
in addition to the expected parameter.
What is the proper way to pass constrained Frege objects to and from Java?
Good question, since this is not explained in the wiki yet.
As in all cases like this, I recommend to use the
:java
command in the REPL. For example:
frege> newPair 1 2.3
frege> :java
You will then get a window that contains among all active definitions one that corresponds to this call. A simple text search can help find the place where newPair
is called. This should help to resolve such issues most of the time.
In your case, the relevant part would look like:
Console.<Integer, Double>numPair(
PreludeBase.INum_Int.it,
PreludeBase.IReal_Double.it,
Thunk.<Integer>lazy(1),
Thunk.<Double>lazy(2.3))
Here is a short overwiew about how type classes and instances are named and how you can get at them.
module x.y.Z where
class Xable where ...
This results in a Java-interface with the fully qualified name
x.y.Z.CXable
And this:
module a.b.C where
import x.y.Z
data MyType ... = ....
instance Xable MyType where ...
results in some class
a.b.C.IXable_MyType /* implements CXable<TMyType> */
If your instance definition does not have constraints themselves, there will be a singleton instance that you can use.
a.b.C.IXable_MyType.it
Otherwise, you need to construct a new instance by passing all constraints as argument to the constructor. For example, the Show instance for
Maybe Int
would look something like this:
new IShow_Maybe(IShow_Int.it)
since the instance head lists a constraint for the Maybe element type:
instance Show a => Show (Maybe a)
Note that you need to know the actual type fully, you can't make a generic type class instance. This is never a problem in Frege itself, as all needed instances are passed to a polymorphic function from the caller. However, as it stands, we don't have constraints in native functions.
Should you need something like this, you can achieve the functionality in most cases by just passing the function you wanted to call as argument.
For example, this doesn't work:
pure native myMethod :: Show a => a -> ...
but this should:
pure native myMethod :: (a -> String) -> a -> ....
myMethod show (Just 47)
The example java code above also reveals that it is not always as easy as described. For example, it so happens that the Double
type doesn't have a separate Num
instance, but just one for Real
which is a subclass of Num
. Unfortunately, only the compiler has the knowledge of what instances are actually present for some type, and which ones are implicit, that is, provided by an instance for a sub-class. Again, the REPL is the best way to find this out.