Type is not as polymorphic as suggested - frege

I'd like to build an abstraction to use different template engines:
class Template a where
process :: a -> Model -> IO String
class TemplateEngine a where
buildTemplate :: (Template b) => a -> BufferedReader -> IO b
My first attempt is to adapt Groovy templates so I implemented the needed data types:
data GroovyWritable = mutable native groovy.lang.Writable where
native writeTo :: GroovyWritable -> Writer -> IO Writer
throws IOException
data GroovyTemplate = mutable native groovy.text.Template where
native make :: GroovyTemplate -> HashMap -> IO GroovyWritable
data GroovyEngine = mutable native groovy.text.markup.MarkupTemplateEngine where
native new :: () -> IO GroovyEngine
native createTemplate :: GroovyEngine -> BufferedReader -> IO GroovyTemplate
throws ClassNotFoundException, IOException
Then I did the correspondent instances:
instance Template GroovyTemplate where
process template model = do -- model is not used at the moment
config <- HashMap.new ()
writable <- GroovyTemplate.make template config
stWriter <- StringWriter.new ()
writer <- writable.writeTo stWriter
writer.toString
instance TemplateEngine GroovyEngine where
buildTemplate engine reader = GroovyEngine.createTemplate engine reader
But the compiler is complaining with:
...
type `GroovyTemplate` is not as polymorphic as suggested
in the annotation where just `α` is announced.
...
type error in expression createTemplate engine reader
type is : IO GroovyTemplate
expected: IO α
Any ideas ? Should I be using a different strategy ?
Thanks
UPDATE:
In order to explain what I'm trying to do I'm adding a function representing a generic way of building a template from a given template engine.
Lets say I haveI understand that Frege needs to be more precise about the types, an instance of TemplateEngine and a BufferedReader containing the content of a template file, executing the buildTemplate function of a given engine should give me in return an instance of Template. This function here is compiling with no warnings at all.
execute :: (TemplateEngine a, Template b) => a -> BufferedReader -> IO b
execute engine reader = buildTemplate engine reader
I'm confused, why compiler is not complaining here ? Shouldn't it be complaining same way it did before ?
UPDATE II (Working Solution):
Following Ingo's recommendation I went through the rationale behind my design and I've found a working solution.
In the beginning I thought it would be great to haveTemplateEngine type class to create template engine instances the same way.
But the most important part was to have a common type class for dealing with templates, among other things, because templates can be cached. So the bottom line is that I don't care how templates are coming from as long as the resulting template is an instance of Template.
Following that premise then I can have a common function to process a template and get the resulting html/json/xml...etc.
execute :: (Template a) => a -> Model -> IO String
execute tpl model = tpl.process model
Of course the production-ready signature should be something like:
execute :: (Template a) => a -> Model -> Either TemplateException String

I'm not entirely sure what you are about to do, but as it stands, the GroovyEngine.createTemplate method cannot be used to instantiate teh GroovyEngine as TemplateEngine. Since the buildTemplate operation promises to return any Template the caller wants, provided that a Template instance is passed as argument.
Now, the first problem here is that native methods can't deal with type class constraints. We could work around this problem by wrapping the call to the native method with a frege function that actually uses the Template constraint. But then again, it is not clear how to actually create an appropriate value, since the Template class doesn't offer a corresponding operation. And the GroovyEngine.createTemplate still doen't qualify, because it always creates a specific template, not one that depends on the constraint.

Related

How to avoid the error "staticCFunction must take an unbound..." in Kotlin Native when a Kotlin callback function is called from C?

This is a general question about callback functions, defined in Kotlin Native, called by C functions.
For argument's sake, let's say I'm trying to walk a directory in a filesystem recursively, using https://linux.die.net/man/3/nftw in Kotlin Native.
(I know there are other ways to do this, using other C functions, but that is not the core of this question.)
nftw() takes a function as a callback:
val directory = "//some/directory"
val callback = kotlinx.cinterop.staticCFunction {
file: CPointer<ByteVar>?,
stat: CPointer<stat>?,
typeFlag: Int,
b: CPointer<FTW>? ->
val fileName = file?.toKString()
println(fileName)
val result = 0
result
}
val depth = 10
val flags = 0
platform.posix.nftw(directory, callback, depth, flags)
This works for listing files via "println()", but as as soon as the lambda contains any captured value, I get the following compiler error:
"kotlinx.cinterop.staticCFunction must take an unbound, non-capturing function or lambda".
My question is: is there any recommended approach on how to
access any non-global state from such a callback?
I did come up with a nasty workaround using a global variable, so that's not what I'm looking for primarily. If there is a commonly accepted solution using #ThreadLocal or something else, please discuss.
For native callbacks in general (not specific to nftw). The C function should accept a void* userData parameter and pass it to the callback when it is called. This allows you to pass local data to the callback, instead of global data.
This is the case even in C/C++.
For this particular case (regardless of language) there isn't really a way to do this without some global data (or JIT but let's not think about it). So any workaround would have to be nasty.
Using #ThreadLocal is a "reasonable nasty" solution.
nftw is just not a well designed C interface.

Scala doobie fragment with generic type parameter

I am trying to abstract inserting objects of different types into sql tables of similar structure. Here's what I'm trying to do:
class TableAccess[A : Meta](table: String) {
def insert(key: String, a: A): ConnectionIO[Unit] = {
(fr"insert into " ++ Fragment.const(table) ++ fr" values ($key, $a);").update.run.map(_ => ())
}
}
But I get this compile error:
[error] diverging implicit expansion for type doobie.util.param.Param[A]
[error] starting with method fromMeta in object Param
[error] (fr"insert into " ++ Fragment.const(table) ++ fr" values ($key, $a);").update.run.map(_ => ())
All I can find in the documentation is:
doobie allows you to interpolate values of any type (and options
thereof) with an Meta instance, which includes...
But it seems that is not enough in this case; what's the right typeclass/imports/conversions I need?
I'll go ahead an answer my own question, almost a year later. I never fully understood what was happening, and I have since updated to a newer version of doobie, so I am not sure how relevant this is. But now the documentation contains this clue:
Note: it is important to understand that Meta exists only to introduce
Get/Put pairs into implicit scope. You should never demand Meta as
evidence in user code: instead demand Get, Put, or both.
def foo[A: Meta](...) // don't do this
def foo[A: Get: Put](...) // ok
And indeed, between that change and the new version, this now compiles just fine for me:
class TableAccess[A: Get: Put](table: String) {
When the compiler is resolving implicit its searches for one of a specific type in the current scope. Here it seems like his finding more than one in his tree search.
It's not a matter of a missing typeclass or imports, it's more like you have too many of them and the compiler cant figure the right one.
Try removing some implicit and see how that works or pass them explicitly.
One way I resolved this was to localize the type parameters (and their evidence) onto the method (on a static/companion object), and then it compiled.
Something like
object MinimalGood {
def good[A: Meta, B: Meta](a: A, b: B): Update0 =
sql"""$a $b""".update
}

What is type of native constructor which throws exception in Frege?

I'm trying to figure out native interface. I'm trying to send some message using UDP. Here what I have:
module UDPTest where
data StringAsBytes = native java.lang.String where
native getBytes :: String -> ST s (Mutable s (JArray Byte))
data InetSocketAddress = native java.net.InetSocketAddress where
native new :: String -> Int -> ST s (Mutable s InetSocketAddress)
data DatagramPacket = native java.net.DatagramPacket where
native new :: Mutable s (JArray Byte) -> Int -> Mutable s InetSocketAddress -> ST s (Mutable s DatagramPacket)
data DatagramSocket = native java.net.DatagramSocket where
native new :: () -> IOMutable DatagramSocket throws SocketException
native send :: Mutable RealWorld DatagramSocket -> MutableIO DatagramPacket -> IO () throws IOException
native close :: MutableIO DatagramSocket -> IO ()
data SocketException = native java.net.SocketException
derive Exceptional SocketException
main _ = do
messageStr = "hello world;\n"
messageAsBytes <- StringAsBytes.getBytes messageStr
address <- InetSocketAddress.new "localhost" 3003
messageLen <- messageAsBytes.getLength
packet <- DatagramPacket.new messageAsBytes messageLen address
socket <- DatagramSocket.new ()
socket.send packet
socket.close
This code accidentally runs but it makes me wonder few things. Firstly, what should be a type of DatagramSocket.new to reflect the fact of throwing exception? I had tried to pack it into Maybe but it ended up in a total mess. Is there any way to do it? For now, I have no idea how to handle exceptions in main and this doesn't address it fully or maybe I'm missing something.
Secondly, Why I was forced by compiler to change InetSocketAddress from pure to impure, to use it in DatagramSocket.new? I was also forced to use mutable version of JArray wherever it was needed in code.
Concerning exceptions: There are 2 ways of managing exceptions.
The first is by wrapping the return type in an Either. This will give you the value you want in Right and the exception in Left when it occures.
To handle the exception, you generally use pattern matching or the either function. Unfortunately, in IO code (like in your case) this would lead to code like
do
r1 <- Socket.new ...
case r1 of
Left -> -- handle exception
Right x -> do
r2 -> x.send ....
case r2 of
....
which is not so nice. Therefore, the Either style is preferred for pure functions, and for IO/ST actions the other style is preferred.
For this, declare your native functions with a throws ... clause, as you have done already for send and new. The exception aware IO/ST action then looks like:
foo = do
s <- Socket.new
d <- s.send ....
...
`catch` (\x1::SocketException -> ...)
`catch` (\x2::IOException -> ....)
....
`finally` finallyaction
There may be as many catches as you need, but make sure to order them so that the most specific one comes before the less specific one, i.e. if ExceptionDerive extends ExceptionSuper, then the catch for ExceptionDerived must occur before the other one.
The finally clause is optional. Note that you don't have access to variables bound in the do block neither in the catch clauses nor in the finally clause. If you need this, you need to do the exception handling on a lower level (i.e., where some variable is bound to the value you need).
Please look up catch and finally in the frege doc or on Froogle.
Make sure the catch is indented less than the code in the do it guards. This is to make sure the compiler sees:
do { .... } `catch` handler
You can as well write code without caring about exceptions, and add them only later. For example, you start with:
action1 a b c = do
dothis a
dothat b
dosomethingelse c
pure whatyouwant
Later, you can rename action1 to action1noex and write
action1 a b c = action1noex a b c
`catch` ....
Second point. For data types that can only be used in the IO Monad, it is recommended to declare them as
data Socket = mutable native java......
This makes it possible to simply write Socket instead of Mutable s Socket or Mutable RealWorld Socket, since the compiler knows that such a value will always be mutable. You can use such types only in native functions that have a IO result.
Conversely, for data types that you just construct but never use in an impure way, you can define them as pure native.
I'm not sure about InetSockAddress but I guess it is not modified once constructed?
Likewise, rgd. the byte array. If you always and only ever want to convert this from and to strings, it can be treated as an utf8 text type (which we unfortunately don't have yet in the library). This would look like
data Charset = pure native java.nio.charset.Charset
pure native utf8 "java.nio.charset.StandardCharsets.UTF_8" :: Charset
data Bytes = pure native "byte[]"
pure native getBytes :: String -> Charset -> Bytes
pure native getString new :: Bytes -> Charset -> String
toBytes s = getBytes s utf8
fromBytes bs = getString bs utf8
(untested, please ignore the warning concerning byte[] for now)
Firstly: you can wrap result of function (method) throwing exception into Either, like this: native fn :: A -> Either SomeException B or sugared version: native fn :: (SomeException | B).
Secondly: Frege values are immutable. If you have got some data type A defined in Frege it is immutable. You are allowed to wrap some Java types and for immutable you mark them pure: data D = pure native com.acme.D. InetSocketAddress is not declared pure. This means that ImmutableSocketAddress can be changed by some other thread anywhere in time(for example closing socket). So Frege compiler marks it as Mutable. You can pass such data to Java functions only wrapped with Mutable taint.
You can write a function in Frege that doesn't need Mutable taint, but to pass it an argument you need to use some readonly or Freezable to get rid of Mutable.

How do I declare Maybe of a mutable type in an non-pure native function in Frege?

The native-gen tool generates the native declaration for the
showOpenDialog method in javafx.stage.FileChooser like so
data FileChooser = mutable native javafx.stage.FileChooser where
native showOpenDialog :: FileChooser -> Window -> IO File
Compiling leads to the message
Non pure native type File must be MutableIO
File in IO actions.
Now setting
native showOpenDialog :: FileChooser -> Window -> MutableIO File
leads to
FileChooser.showOpenDialog has an illegal
return type for a method that is not pure, perhaps ST s (MutableIO
File) would work
but following the advice leads to first error message again.
The compiler accepts IOMutable File as return type, which makes sense
since it is an IO action that returns a mutable type.
If possible, the compiler error message should be adapted to avoid frustration on the user side.
However, in this special situation, the file can be null and so
the core type is not File but Maybe File.
But then just using IOMutable (Maybe File) leads to the rather surprising message
The type MutableIO (Maybe File) is illegal,
Maybe File must be a native type.
Any advice on how to properly declare this type?
The code generated by native-gen is wrong because File has been declared as IO in native-gen but File is actually defined as a stateful (not IO) native type as can be seen from here.
IOMutable is defined as type IOMutable d = IO (MutableIO d).
For your case, the mutable native type (MutableIO d) can be null so the following should work:
data FileChooser = mutable native javafx.stage.FileChooser where
native showOpenDialog :: FileChooser -> Window -> IO (Maybe (MutableIO File))

Yesod/Persistent testing with bracket pattern

I'm very new to Haskell, so I'm having trouble absorbing all of the advanced features used in Yesod such as type instances and equality constraints. I am trying to implement the bracket pattern in Yesod's test framework in order to get setUp/tearDown functionality. Here's what I've got so far (updated via edit):
module FishMother where
import Control.Exception.Lifted
import TestImport
import Database.Persist
import Database.Persist.GenericSql
import Model
insertYellowfinTuna :: OneSpec Connection FishId
insertYellowfinTuna = runDB . insert $ Fish "Yellowfin Tuna"
deleteFish :: FishId -> OneSpec Connection ()
deleteFish = runDB . delete
withYellowfinTuna :: FishId -> OneSpec Connection ()
withYellowfinTuna = bracket insertYellowfinTuna deleteFish
The compile errors are as follows:
tests/FishMother.hs:18:21:
Couldn't match type `FishId
-> Control.Monad.Trans.State.Lazy.StateT
(Yesod.Test.OneSpecData Connection) IO ()'
with `Key SqlPersist Fish'
Expected type: FishId -> OneSpec Connection ()
Actual type: (FishId
-> Control.Monad.Trans.State.Lazy.StateT
(Yesod.Test.OneSpecData Connection) IO ())
-> Control.Monad.Trans.State.Lazy.StateT
(Yesod.Test.OneSpecData Connection) IO ()
In the return type of a call of `bracket'
In the expression: bracket insertYellowfinTuna deleteFish
In an equation for `withYellowfinTuna':
withYellowfinTuna = bracket insertYellowfinTuna deleteFish
What am I doing wrong?
After rereading the question, I think the simple answer is to use a lifted bracket, which will handle all of the transformer issues. I'll leave my original answer as well, as it might give a bit more insight into what's happening.
The problem in this case is the usage of liftIO. Let's look at the type signature:
liftIO :: MonadIO m => IO a -> m a
What this means is that you can take an arbitrary I/O action (e.g., reading from a file) and run it in any monad which allows I/O to be performed, such as the database monad. However, what you're trying to do is really the opposite: run a database monad action as just a normal I/O action. This can't be directly done, since the database actions rely on extra context- specifically a database connection- which the IO monad doesn't provide.
So how do you turn a database action into an IO action? We have to unwrap. Unwrapping is a common activity for monad transformers, which can be thought of as layers added on top of each other. Lifting (as in liftIO) allows you to take an action from a lower layer and move it up to a higher layer. Unwrapping takes a layer off. Since how you unwrap depends on the specific transformer, each transformer has its own unwrap functions.
In the case of Persistent, you can use withSqliteConn or the equivalent for your backend, see the synopsis in the Persistent chapter for more details.