Description
There are a number of differences in the semantics of Morphir compared to Scala which makes it challenging to come up with a consistent mapping. Let's start with a simple SDK function of List.map
:
map : (a -> b) -> List a -> List b
The direct Scala mapping of this would be:
def map[A, B](f: A => B)(l: List[A]): List[B]
There are multiple things here that are not idiomatic. Here is how the idiomatic version would look like:
class List[A] {
def map[B](f: A => B): List[B]
}
There are a number of differences between the approaches:
- Since Scala comes from an OOP background it prefers using methods to implement functionality that belongs to a specific type so this function would normally be a method on the type itself.
- Since Morphir is pure FP all functions are curried by default. In Scala this can be done but looks unnatural and makes type-inference more difficult.
- Ordering of arguments is the opposite of what would be natural in Scala. In Scala the last argument would be the mapping function
f
. This makes type-inferencing difficult because it's generally applied left-to-right.
We can generalize the mapping approach to the following. Given this Morphir model:
type T = ...
fun : Arg1 -> Arg2 -> ... -> ArgN -> T -> R
The generated Scala should be:
class T {
def fun(arg1: Arg1, arg2: Arg2, ..., argN: ArgN): R
}
This will work and look natural in most cases but there are edge cases:
map2 : (a -> b -> c) -> List a -> List b -> List c
This function doesn't have a trivial method mapping since the type appears multiple times in the argument list. It seems that a better approach here is to use a static method/function but still avoid currying and put the lists into the front:
def map2[A, B, C](la: List[A], lb: List[B], f: (A,B)=> C): List[C]
This is more difficult to formalize.