Search code examples
f#suave

Sample Suave.IO does not compile in my F# project


I'm trying to get this example from Suave.io compiling for a simple F# project: http://suave.io/

open Suave.Http.Applicatives
open Suave.Http.Successful
open Suave.Web
open Suave.Types
open Suave.Model

let greetings q =
  defaultArg (q ^^ "name") "World" |> sprintf "Hello %s"

let sample : WebPart = 
  path "/hello" >>= choose [
    GET  >>= request(fun r -> OK <| greetings (query r))
    POST >>= request(fun r -> OK <| greetings (form r))
    NOT_FOUND "Found no handlers" ]

Unfortunately I'm getting a compiler error on the (query r) part:

error FS0001: Expecting a type supporting the operator '^^' but given a function type. You may be missing an argument to a function.

I've tried to narrow down the compiler error to a few simple lines and now have this:

let greetings q =
  defaultArg (q ^^ "name") "World" |> sprintf "Hello %s"

let q (rqst : string) = query rqst
let t = greetings q

And now get that same compiler error on the greetings q line. The types in my example above are:

query:
  string -> (string -> Choice<'T,string>) -> HttpRequest -> Choice<'T,string>

greetings: 
 (string -> (string -> Choice<obj,string>) -> HttpRequest -> Choice<obj, string>) -> string

q:
  string -> ((string -> Choice<'a, string>) -> HttpRequest -> Choice<'a, string>)

So, my types aren't matching but I'm not too sure how I'd get these to match up.

Is the example just out of date? Any ideas how I can get this example to compile and run?

I'm running the RC build of Visual Studio 2015

Thanks


Solution

  • I'm not familiar with Suave.IO, but looking at their source code, it indeed looks like an old sample code that no longer works. The definition of the query function is as follows:

    let query queryKey f (req : HttpRequest) =
      req.queryParam queryKey
      |> Choice.from_option (sprintf "Missing query string key '%s'" queryKey)
      |> Choice.bind f
    

    Note the three arguments - you're only passing the request, so the return value is not a value (or a collection), it's a function with two arguments.

    On the other hand, the operator ^^ is used to retrieve a value from a collection by key.

    Going through the history, it indeed seems that this is an obsolete and actually broken way of retrieving the collection of query parameters. The proper way now seems to be like this:

    GET  >>= request(fun r -> OK <| greetings r.query)
    POST >>= request(fun r -> OK <| greetings r.form)