2

我正在为一个新项目寻找一种语言。它是基于 Web 的项目,我想采用 REST 架构。

我还想要一种函数式编程语言。我可以在 Haskell(因为它很酷)和 Scala(因为 Play Framework)之间做出选择。

经过几次研究以找出这与语言之间的主要区别后,我发现了 Frege,一种在 JVM 上运行的类似 Haskell 的语言。

所以我的问题是,因为 Frege 在 JVM 上运行,是否可以将 Play 框架与 Frege 一起使用?

4

1 回答 1

5

这是一个简单的应用程序来演示我们如何在 Play 中使用 Frege。由于 Play 支持 Java,因此使用 Frege 的 Java API 实际上非常容易,即使我们还没有对 Frege 的原生 Play 支持。该应用程序基本上是 JSON 输入和 JSON 输出。Frege 程序从 JSON 请求中读取参数,POST并以向用户致意的 JSON 响应进行响应。

播放conf/routes

POST     /greet                      helloplay.FregeApplication.greet()

现在弗雷格中的实际“业务逻辑”:

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()))
        );
    }
}

在这里,我们定义了 2 种类型,分别对应于请求和响应以及 JSON 转换,用于具有FromJSONToJSON类型类实例的那些。该webMain函数接受 play并从 JSON 请求Request中读取数据,并返回包装在 play 中的 JSON 响应。该函数是为 Play 控制器提供实现的函数。播放控制器是一个扩展 Play 的类。我们可以通过声明一个内部的 Frege 源文件来使 Frege 模块扩展一个 Java 类。该函数也是一个 IO 操作,因此我们必须在某个时候评估发生的事情,这就是底部 Controller 中的 Java 方法通过调用 Frege 所做的nameResult.StatuswebMainplay.mvc.Controllernative modulewebMainST.performUnsafe然后从可能的 thunk 中强制结果,否则应用程序只会预热 CPU :)

这里的类型和函数都来自 Play 框架Request,所以我们必须为 Frege 添加原生绑定,提及它们的纯度或可能的 null 值等。这是一件好事,因为 Frege 是一种纯语言并且没有的概念,我们必须明确提及副作用或编译器可能的 null 值,这与 Scala 不同,您可以调用任何 Java 方法。ResultStatusPlayControllerokbadRequestnullMaybe

Play 的 Frege 原生绑定:

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

这就对了!我们可以运行它:

activator run

接着

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

{"message" : "Hello, PlayFrege"}

Frege 有一个SBT 插件,可用于在 Play 项目中编译 Frege 源代码。如果有人想尝试一下,我已经在Github中推送了这个示例应用程序。

于 2015-11-20T05:59:19.970 回答