2

I'm searching a language for a new project. It's web based project and I want to adopt a REST architecture.

I also want a function programming language. I have the choice between Haskell (because it's cool) and Scala (because of the Play Framework).

After few researches to find out the main differences between this to languages, I have found Frege, an Haskell like language running on the JVM.

So my question is, because Frege is running on the JVM, is it possible to use Play framework with Frege ?

Ingo
  • 36,037
  • 5
  • 53
  • 100
Emrys Myrooin
  • 2,179
  • 14
  • 39
  • 2
    Note that frege has its own tag on SO. I changed the tags accordingly, as probably the people hanging around in the Haskell thread cannot say much about it. Even I cannot answer it, since I don't know wtf PLAY is. – Ingo Nov 18 '15 at 19:39
  • 2
    It should definitely be possible. If it is possible with Java, porting that to Frege wouldn't be that hard. I once actually ported [an Akka example](http://stackoverflow.com/questions/17256979/akka-with-frege-running-slower-than-scala-counterpart) to Frege. I'll try Play with Frege and post an example later as I am not my computer now. – Marimuthu Madasamy Nov 18 '15 at 20:21
  • @Marimuthu From what I have seen of this language, every external object and fonctions have to be declared somwhere un the code as native call to existing implementation un th JVM (that seems logical). So i suppose that i have to add the définition of evry Play API's objects that I want to use. Am i right ? – Emrys Myrooin Nov 18 '15 at 20:44
  • @EmrysMyrooin True. You can do it incrementally, just defininig the types you really need (and within the types only the methods you really need). Or you can do it all at once using the native-gen tool. However, the lataer usually requires some inspection and manual maintenance. – Ingo Nov 18 '15 at 20:56
  • Is this for a work project or a hobby project? If it is for work I would suggest just using scala. Otherwise, why not look at rust? – Rüdiger Klaehn Nov 19 '15 at 08:27
  • @Rüdiger Klaehn Yes it's for work project. I'm talking about Functional Programming... If Scala is part of my choices it's only for the Play Framwork, not for the language him self. I prefere Haskell but the web framework available are not as good as Play. Rust is not what I expect. – Emrys Myrooin Nov 19 '15 at 09:41
  • Aren't there comparable REST frameworks for haskell? Using play from frege seems like a very exotic combination. It might work, but it will be hard to maintain. – Rüdiger Klaehn Nov 19 '15 at 10:04
  • Yes there is some but there are far more complicated (in my opinion) – Emrys Myrooin Nov 19 '15 at 10:29
  • @Ingo I think that he is not complaning for Frege beeing hard to maintain be for using play with Frege – Emrys Myrooin Nov 20 '15 at 07:22
  • @RüdigerKlaehn Apparently the misunderstanding is on my side and I'll remove my comment (and this one later). – Ingo Nov 20 '15 at 10:17

1 Answers1

5

Here is a simple application to demonstrate how we can use Frege with Play. Since Play supports Java, it is actually very easy to use the Java API from Frege even though we don't have native Play support for Frege yet. The application is basically JSON-in and JSON-out. A Frege program reads a parameter from a JSON POST request and responds with a JSON response that greets the user.

Play conf/routes:

POST     /greet                      helloplay.FregeApplication.greet()

Now the actual "business logic" in Frege:

module helloplay.FregeApplication where

import Data.JSON
import helloplay.Play

data GreetingRequest = GreetingRequest { name :: String }

data GreetingResponse = GreetingResponse { message :: String }

instance FromJSON GreetingRequest where
   fromJSON (Struct fs)  = do
        name <- field "name" fs
        pure $ GreetingRequest name
   fromJSON invalid = fail ("Invalid JSON for Greeting Request: " ++ show invalid)

instance ToJSON GreetingResponse where
    toJSON (GreetingResponse message) = Struct [ assoc "message" message ]

greet :: GreetingRequest -> GreetingResponse
greet request = GreetingResponse $ "Hello, " ++ request.name

webMain :: Request -> IO ResultStatus
webMain request = do
  let jsonRequest = parseJSON request.body.asJson.toString
  return $ either badRequest (ok . show . toJSON . greet) jsonRequest

{-
 - This makes the Frege module extend Play Controller class so that it can be configured to handle a route.
 -}
native module type PlayController where {
    public static play.mvc.Result greet() {
        return frege.runtime.Delayed.forced(
          frege.prelude.PreludeBase.TST.performUnsafe(webMain(request()))
        );
    }
}

Here we have defined 2 types corresponding to request and response and JSON conversions for those with FromJSON and ToJSON type class instances. The webMain function takes the play Request and reads name from JSON request and returns a JSON response wrapped in play's Result.Status. The webMain function is the one which provides an implementation for a Play controller. A play controller is a class which extends Play's play.mvc.Controller. We can make a Frege module extend a Java class by declaring a native module inside Frege source file. The webMain function is also an IO action so we have to evaluate at some point for something to happen which is what the Java method in the Controller at the bottom does by invoking Frege's ST.performUnsafe and then forcing the result from a possible thunk otherwise the application would just warm up the CPU :)

Here the types like Request, ResultStatus, PlayController and functions like ok, badRequest are all from Play framework so we have to add native bindings for Frege mentioning their purity or possible null values etc. This is a good thing as Frege is a pure language and doesn't have a notion of null, we have to explicitly mention side effects or Maybe for possible null values for the compiler unlike Scala where you can just call any Java methods.

The Frege native bindings for Play:

module helloplay.Play where

data PlayController = native play.mvc.Controller

data Result = pure native play.mvc.Result

data ResultStatus = pure native play.mvc.Results.Status

pure native badRequest play.mvc.Results.badRequest :: String -> ResultStatus

data Request = pure native play.mvc.Http.Request where
  pure native body :: Request -> RequestBody

data RequestBody = pure native play.mvc.Http.RequestBody where
  pure native asText :: RequestBody -> String
  pure native asJson :: RequestBody -> JsonNode

data JsonNode = pure native com.fasterxml.jackson.databind.JsonNode where
  pure native asText :: JsonNode -> String
  pure native toString :: JsonNode -> String

pure native ok play.mvc.Results.ok :: String -> ResultStatus

That is it! We can run it with:

activator run

and then

$ curl --header "Content-type: application/json" --request POST --data '{"name": "PlayFrege"}' http://localhost:9000/greet

{"message" : "Hello, PlayFrege"}

Frege has an SBT plugin that can be used to compile Frege sources in a Play project. I have pushed this sample application in Github if anyone wants to try it out.

Marimuthu Madasamy
  • 13,126
  • 4
  • 30
  • 52
  • Great work, as always, Marimuthu! I have a question, though: why can't we just say `request.body.asText` instead `toJson.toString` ? – Ingo Nov 20 '15 at 07:36
  • Okey it seems to work but i think it's litle hacky... I want to use this for a work and serious project and I loose here some of automation power greeted buy thé play framework like the JSON parsing and data base management. But I keep this un mind for some personal projects, waiting for play port to frege – Emrys Myrooin Nov 20 '15 at 07:57
  • Thanks Ingo! I tried that first but it doesn't seem to work for JSON requests. – Marimuthu Madasamy Nov 20 '15 at 15:27
  • @Emrys Fair enough. Yes, with native play support, you would get all those automation but I don't think there is anything hacky here. And of course, I can understand that you don't want to do this at work project but being JVM languages, you could mix Frege with your Java and Scala code and get some benefit of pure FP. If you do try this out, I'd be happy to get your feedback. – Marimuthu Madasamy Nov 20 '15 at 15:39
  • Yes I think that I will try to do all the web management stuff with Play and Scala and only delegate the fonctional part to Frege modules. I think it can be a pretty cool – Emrys Myrooin Nov 20 '15 at 16:03
  • It turned out that we don't need a separate Java source file to implement a Play controller. We can just do it in Frege. I have updated the answer and also added a Github link to the complete source code. – Marimuthu Madasamy Nov 23 '15 at 06:01