Scala Code demystify

2019-04-05 14:10发布

问题:

Could someone demystify this code which is part of the zentasks example in the Play20 framework. I'm curious how this works, granted I'm new to Scala from Java so a lot of things are tough to wrap my head around.

def IsAuthenticated(f: => String => Request[AnyContent] => Result) = 
  Security.Authenticated(username, onUnauthorized) { user =>
    Action(request => f(user)(request))
  }

回答1:

You need to split up the signature a bit. f is a function that takes a not-yet-computed string => String and returns another function that accepts a Request[AnyContent] and returns a result.

The Security.Authenticated call accepts two parameters lists. One that has username and onUnauthorized. The second takes a function accepting the user and returning an action.

The Action.apply method accepts a function Request[AnyContent] => Result

so, the f is called in 'curried' fashion. That is the first function is called, and then the resulting function is immediately used f(user)(request).

Here's the same thing desugared (at least, as best I can) and ugly:

def isAuthenticated(f: => String => Request[AnyContent] => Result) =
  Security.Authenticated(username, onUnauthorized) { user: String =>
     Action.apply { request: Request[AnyContent] =>
       val hiddenTmp: Request[AnyContent] => Result = f(user)
       hiddenTemp.apply(request)
     }
  }

You can see the compiler is doing a bit of work removing type annotations. Hopefully that helps explain how it desugars into raw scala. Essentially, the function does a lot of functional composition.



回答2:

First off a user guide to my answer: I will use italics to indicate a function that is used without being explicitly named (see anonymous functions).

IsAuthenticated is a method which takes as a parameter an argument f.

f is a function which takes Y as a parameter and produces an instance of Result

Y is a function which takes Z as a parameter and produces an instance of Request[AnyContent]

Z is a function which takes no parameters and returns a String

IsAuthenticated calls Security.Authenticated, passing username and onUnauthorized (a function to call when the user is not authorized to perform the requested action).

I am not entirely sure what's going on past here myself- I'm not quite that good with Scala yet- but my guess is that Security.Authenticated is a case class, and the following is equivalent to subclassing it and adding a constructor in java:

{
  Action(request => f(user)(request))
}

If that much of my assumption is correct, then Action (which is a method on Security.Authenticated) is being called, passing as an argument a A.

A is a function which takes a Request object (I am guessing at this class name) and produces a Result. The use of Result is implied here because the implementation of A is a call to f.

So when the subclass of Security.Authenticated is instanciated, Action is called, which authenticates the user for some action (specified as a String) and then if the user is authenticated, returns f (the original parameter) which is presumably called by Action (after the aforementioned authentication). This call to f returns a Result, which is also a function. Result is then finally called with request (which was passed to A) as a parameter.