8000 Implement List.foldl and Dict.filter by deusaquilus · Pull Request #364 · finos/morphir-scala · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Implement List.foldl and Dict.filter #364

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ MyBug.scala

# Elm build products
elm-stuff/
elm.json

# Docusaurus generated folders
website/translated_docs/
Expand Down Expand Up @@ -440,6 +441,7 @@ website/static/api

.bsp/
.vscode/settings.json
.vscode/

build.user.sbt
build.user.properties
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,15 @@
"src/Morphir/Examples/App/ConstructorTests.elm": "56fdf0bd81a5d4b51e8e94cf16d01c05",
"src/Morphir/Examples/App/CurrentTest.elm": "7217989153ede6e82dfe1edb324e8aa5",
"src/Morphir/Examples/App/DestructureTests.elm": "130b60a9f5c1f62b9e1394b2b1b74339",
"src/Morphir/Examples/App/DictionaryTests.elm": "390e97f736705dda19b902b10bfd18a2",
"src/Morphir/Examples/App/DictionaryTests.elm": "4dd8cb526ee1cc0fe2515d77eb0dcf36",
"src/Morphir/Examples/App/EllieStuff.elm": "f9259184f634d714dabcd8ec90f07e7a",
"src/Morphir/Examples/App/EnumTest.elm": "1bdb50499357960926f3ffe7984a83c0",
"src/Morphir/Examples/App/ExampleModule.elm": "e90c60dd8d4756d55d91efd7923a8cca",
"src/Morphir/Examples/App/IfThenElseTests.elm": "14a9cc5c50253e40c42757f40a6682a7",
"src/Morphir/Examples/App/LambdaTests.elm": "09090aa4162a5142e4b80c9209f0f6c4",
"src/Morphir/Examples/App/LetDefinitionTests.elm": "b8981542e487ee7ade8b90e1e2a6073d",
"src/Morphir/Examples/App/LetRecursionTests.elm": "e66cd3a8d23cc3c5e0e3f65fc21f7618",
"src/Morphir/Examples/App/ListTests.elm": "7df9f9f480f9460d1d8df607beafba24",
"src/Morphir/Examples/App/ListTests.elm": "ad47332795940df6dddcd98dfbc3d38b",
"src/Morphir/Examples/App/LiteralTests.elm": "6f06586ae6503c5293c64d16e0360bd3",
"src/Morphir/Examples/App/LocalDateTests.elm": "a77f3af4f0f5e327de55bc8e09bea568",
"src/Morphir/Examples/App/LocalTimeTests.elm": "73b42eb147386ec56135f2902f218995",
Expand Down
52,341 changes: 29,692 additions & 22,649 deletions examples/morphir-elm-projects/evaluator-tests/morphir-ir.json

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@ import Dict exposing (Dict)
{-
-}

dictFilterTest: () -> Dict Int String
dictFilterTest _ =
let
dict = Dict.fromList [(1, "Red"), (2, "Blue"), (3, "Blue"), (4, "Blue"), (5, "Green")]
in
Dict.filter (\k v -> k > 2 && v == "Blue") dict

--Test: Dict/fromList
dictFromListTest : () -> Dict Int String
dictFromListTest _ =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
module Morphir.Examples.App.ListTests exposing (..)
import List exposing (..)
import Dict
import Dict exposing (Dict)



Expand Down Expand Up @@ -67,6 +69,18 @@ listFilterTest _ =
filter (\n -> n > 3) [3,4,5,6]
--expected = [4,5,6]

--Test: List/FoldLeft
listFoldLeftTest : () -> String
listFoldLeftTest _ =
foldl (\elem acc -> acc ++ elem ++ "|") "<" ["foo","bar","baz"]
--expected = [4,5,6]

--Test: List/FoldLeft - Advanced
listFoldLeftAdvTest : () -> Dict String Int
listFoldLeftAdvTest _ =
foldl (\elem acc -> Dict.insert elem (String.length elem) acc) Dict.empty ["foo","barr","bazzz"]
--expected = [Dict (foo, 3), (barr, 4), (bazzz, 5)]

--Test: List/Map
listMapTest : () -> List Int
listMapTest _ =
Expand Down
80 changes: 72 additions & 8 deletions morphir/runtime/src/org/finos/morphir/runtime/quick/Native.scala
Original file line number Diff line number Diff line change
@@ -1,12 +1,31 @@
package org.finos.morphir.runtime.quick

import org.finos.morphir.ir.Type
import org.finos.morphir.naming._
import org.finos.morphir.naming.*
import org.finos.morphir.runtime.UnsupportedType
import org.finos.morphir.runtime.quick.Result.Primitive

import scala.collection.mutable

object DictSDK {
val filter: SDKValue[Unit, Type.UType] = SDKValue.SDKNativeInnerFunction {
NativeFunctionSignatureAdv.Fun2 {
(store: Store[Unit, Type.UType]) => (f: Result[Unit, Type.UType], l: Result[Unit, Type.UType]) =>
{
val dictMap = l.unwrapMap
val newDict =
dictMap.filter { case (k, v) =>
val partialAppliedF =
Loop.handleApplyResult[Unit, Type.UType](Type.UType.Unit(()), f, k, store)
val result =
Loop.handleApplyResult[Unit, Type.UType](Type.UType.Unit(()), partialAppliedF, v, store)
result.unwrapBoolean
}
Result.MapResult(newDict)
}
}
}

val fromList: SDKValue[Unit, Type.UType] = SDKValue.SDKNativeFunction.fun1 {
(l: Result[Unit, Type.UType]) =>
val list = l.asInstanceOf[Result.ListResult[Unit, Type.UType]].elements
Expand All @@ -22,9 +41,11 @@ object DictSDK {
Result.MapResult(mapped)
}

val empty: SDKValue[Unit, Type.UType] = SDKValue.SDKNativeValue(Result.MapResult(mutable.LinkedHashMap()))

val get: SDKValue[Unit, Type.UType] = SDKValue.SDKNativeFunction.fun2 {
(key: Result[Unit, Type.UType], m: Result[Unit, Type.UType]) =>
val map = m.asInstanceOf[Result.MapResult[Unit, Type.UType]].elements
val map = m.unwrapMap
map.get(key) match {
case Some(value) => Result.ConstructorResult(
FQName.fromString("Morphir.SDK:Maybe:just"),
Expand All @@ -37,12 +58,40 @@ object DictSDK {
}
}

val insert: SDKValue[Unit, Type.UType] = SDKValue.SDKNativeFunction.fun3 {
(key: Result[Unit, Type.UType], value: Result[Unit, Type.UType], m: Result[Unit, Type.UType]) =>
val map = m.unwrapMap.clone() // because LinkedHashMap is mutable MAKE SURE TO CLONE IT before inserting things
map += ((key, value))
Result.MapResult(map)
}

val sdk: Map[FQName, SDKValue[Unit, Type.UType]] = Map(
FQName.fromString("Morphir.SDK:Dict:fromList") -> fromList,
FQName.fromString("Morphir.SDK:Dict:get") -> get
FQName.fromString("Morphir.SDK:Dict:get") -> get,
FQName.fromString("Morphir.SDK:Dict:filter") -> filter,
FQName.fromString("Morphir.SDK:Dict:insert") -> insert,
FQName.fromString("Morphir.SDK:Dict:empty") -> empty
)
}
object ListSDK {
val foldl: SDKValue[Unit, Type.UType] = SDKValue.SDKNativeInnerFunction {
NativeFunctionSignatureAdv.Fun3 {
(store: Store[Unit, Type.UType]) =>
(f: Result[Unit, Type.UType], first: Result[Unit, Type.UType], l: Result[Unit, Type.UType]) =>
{
val list = l.unwrapList
list.foldLeft(first) { (b, a) => // Note that elm does (a, b) => b, scala does it in the opposite way
val partialAppliedF =
Loop.handleApplyResult[Unit, Type.UType](Type.UType.Unit(()), f, a, store)
val result =
Loop.handleApplyResult[Unit, Type.UType](Type.UType.Unit(()), partialAppliedF, b, store)

result
}
}
}
}

val append: SDKValue[Unit, Type.UType] = SDKValue.SDKNativeFunction.fun2 {
(a: Result[Unit, Type.UType], b: Result[Unit, Type.UType]) =>
val listA = a.asInstanceOf[Result.ListResult[Unit, Type.UType]]
Expand All @@ -56,6 +105,7 @@ object ListSDK {
Result.ListResult(a :: listB.elements)
}
val sdk: Map[FQName, SDKValue[Unit, Type.UType]] = Map(
FQName.fromString("Morphir.SDK:List:foldl") -> foldl,
FQName.fromString("Morphir.SDK:List:append") -> append,
FQName.fromString("Morphir.SDK:List:cons") -> cons
)
Expand Down Expand Up @@ -88,6 +138,10 @@ object SetSDK {
}

object StringSDK {
val length: SDKValue[Unit, Type.UType] =
SDKValue.SDKNativeFunction.fun1((arg: Result[Unit, Type.UType]) =>
Result.Primitive.Int(arg.unwrapString.length)
)
val append: SDKValue[Unit, Type.UType] =
SDKValue.SDKNativeFunction.fun2((a: Result[Unit, Type.UType], b: Result[Unit, Type.UType]) =>
Result.Primitive.String(a.unwrapString + b.unwrapString)
Expand All @@ -98,7 +152,8 @@ object StringSDK {
)
val sdk: Map[FQName, SDKValue[Unit, Type.UType]] = Map(
FQName.fromString("Morphir.SDK:String:append") -> append,
FQName.fromString("Morphir.SDK:String:right") -> right
FQName.fromString("Morphir.SDK:String:right") -> right,
FQName.fromString("Morphir.SDK:String:length") -> length
)
}
object Native {
Expand Down Expand Up @@ -165,16 +220,25 @@ object Native {
}

val toFloat: SDKValue[Unit, Type.UType] = SDKValue.SDKNativeFunction.fun1 {
(a: Result[Unit, Type.UType]) => Result.Primitive.Double(Result.unwrap(a).asInstanceOf[Long].toDouble)
(a: Result[Unit, Type.UType]) =>
val output =
a.unwrapNumeric match {
case Primitive.Int(value) => value.toDouble
case Primitive.Long(value) => value.toDouble
case Primitive.Double(value) => value
case Primitive.BigDecimal(value) => value.toDouble
case Primitive.Float(value) => value.toDouble
}
Result.Primitive.Double(output)
}
val log: SDKValue[Unit, Type.UType] = SDKValue.SDKNativeFunction.fun2 {
(a: Result[Unit, Type.UType], b: Result[Unit, Type.UType]) =>
val denominator = Math.log(Result.unwrap(a).asInstanceOf[Double])
val denominator = Math.log(a.unwrapDouble)
val asDouble =
if (denominator == 0)
Double.PositiveInfinity
else
Math.log(Result.unwrap(b).asInstanceOf[Double]) / denominator
Math.log(b.unwrapDouble) / denominator
Result.Primitive.Double(asDouble)
}

Expand Down Expand Up @@ -204,7 +268,7 @@ object Native {
}
val isEmpty: SDKValue[Unit, Type.UType] = SDKValue.SDKNativeFunction.fun1 {
(l: Result[Unit, Type.UType]) =>
val list = l.asInstanceOf[Result.ListResult[Unit, Type.UType]].elements
val list = l.unwrapList
Result.Primitive.Boolean(list.length == 0)
}
val filter: SDKValue[Unit, Type.UType] = SDKValue.SDKNativeInnerFunction {
Expand Down
19 changes: 16 additions & 3 deletions morphir/runtime/src/org/finos/morphir/runtime/quick/Result.scala
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ sealed trait Result[TA, VA] {
def unwrapString = Result.unwrapString(this)
def unwrapInt = Result.unwrapInt(this)
def unwrapBoolean = Result.unwrapBoolean(this)
def unwrapDouble = Result.unwrapDouble(this)
def unwrapLong = Result.unwrapLong(this)
def unwrapPrimitive = Result.unwrapPrimitive(this)
def unwrapNumeric = Result.unwrapNumeric(this)
Expand Down Expand Up @@ -52,7 +53,7 @@ object Result {
case Result.ListResult(list) => list
case _ =>
throw new UnexpectedType(
s"Cannot unwrap the value `${arg}` into a primitive ListResult value. It is not a list result!"
s"Cannot unwrap the value `${arg}` into a ListResult value. It is not a list result!"
)
}

Expand All @@ -61,7 +62,7 @@ object Result {
case Result.MapResult(map) => map
case _ =>
throw new UnexpectedType(
s"Cannot unwrap the value `${arg}` into a primitive ListResult value. It is not a list result!"
s"Cannot unwrap the value `${arg}` into a MapResult value. It is not a list result!"
)
}

Expand All @@ -76,6 +77,17 @@ object Result {
throw new UnexpectedType(s"Cannot unwrap the value `${arg}` into a primitive Boolean. It is not a primitive!")
}

def unwrapDouble[TA, VA](arg: Result[TA, VA]): Double =
arg match {
case Primitive.Double(v) => v
case _: Primitive[_, _, _] =>
throw new UnexpectedType(
s"Could not unwrap the primitive `${arg}` into a Double value because it was not a Primitive.Double"
)
case _ =>
throw new UnexpectedType(s"Cannot unwrap the value `${arg}` into a primitive Double. It is not a primitive!")
}

def unwrapInt[TA, VA](arg: Result[TA, VA]): Int =
arg match {
case Primitive.Int(v) => v
Expand Down Expand Up @@ -124,7 +136,7 @@ object Result {
def unwrapNumeric[TA, VA](arg: Result[TA, VA]): Primitive.Numeric[TA, VA, _] =
arg match {
case p: Primitive.Numeric[_, _, _] => p.asInstanceOf[Primitive.Numeric[TA, VA, _]]
case _ => throw new UnexpectedType(s"Cannot unwrap the value `${arg}` into a primitive")
case _ => throw new UnexpectedType(s"Cannot unwrap the value `${arg}` into a primitive numeric")
}

case class NumericsWithHelper[T](
Expand Down Expand Up @@ -227,6 +239,7 @@ object Result {
lazy val fractionalHelper = Some(implicitly[scala.Fractional[scala.BigDecimal]])
lazy val integralHelper = None
}
// TODO Morphir Float type is a double, why do we have this???
case class Float[TA, VA](value: scala.Float) extends Numeric[TA, VA, scala.Float] {
val numericType = Numeric.Type.Float
lazy val numericHelper = implicitly[scala.Numeric[scala.Float]]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,16 @@ object EvaluatorMDMTests extends MorphirBaseSpec {
Data.Boolean(true),
Data.Boolean(false)
)),
testEvaluation("Fold Left")("listTests", "listFoldLeftTest")(
Data.String("<foo|bar|baz|")
),
testEvaluation("Fold Left Advanced")("listTests", "listFoldLeftAdvTest")(
Data.Map(
Data.String("foo") -> Data.Int(3),
Data.String("barr") -> Data.Int(4),
Data.String("bazzz") -> Data.Int(5)
)
),
testEvalMultiple("Append (and infer type")(
"ListTests",
"listAppend",
Expand Down Expand Up @@ -588,7 +598,11 @@ object EvaluatorMDMTests extends MorphirBaseSpec {
(Data.Int(4), Data.String("White")),
(Data.Int(5), Data.String("Green"))
)),
testEvaluation("Get")("dictionaryTests", "dictGetTest")(Data.Optional.Some(Data.String("Cat")))
testEvaluation("Get")("dictionaryTests", "dictGetTest")(Data.Optional.Some(Data.String("Cat"))),
testEvaluation("Filters a dictionary")("dictionaryTests", "dictFilterTest")(Data.Map(
(Data.Int(3), Data.String("Blue")),
(Data.Int(4), Data.String("Blue"))
))
),
suite("Optional Tests")(
testEvaluation("Returns a Just 1")("optionTests", "returnJustIntTest")(Data.Optional.Some(Data.Int(1))),
Expand Down
0