diff --git a/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res b/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res index 19749ff7c7..34d1fb4df6 100644 --- a/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res +++ b/packages/squiggle-lang/__tests__/SquiggleLibrary/SquiggleLibrary_FunctionRegistryLibrary_test.res @@ -87,6 +87,8 @@ describe("FunctionRegistry Library", () => { "Error(Error: Too few samples when constructing sample set)", ) + testEvalToBe("Dict.set({a: 1, b: 2}, 'c', 3)", "Ok({a: 1,b: 2,c: 3})") + testEvalToBe("d={a: 1, b: 2}; _=Dict.set(d, 'c', 3); d", "Ok({a: 1,b: 2})") testEvalToBe("Dict.merge({a: 1, b: 2}, {b: 3, c: 4, d: 5})", "Ok({a: 1,b: 3,c: 4,d: 5})") testEvalToBe( "Dict.mergeMany([{a: 1, b: 2}, {c: 3, d: 4}, {c: 5, e: 6}])", @@ -96,6 +98,7 @@ describe("FunctionRegistry Library", () => { testEvalToBe("Dict.values({a: 1, b: 2})", "Ok([1,2])") testEvalToBe("Dict.toList({a: 1, b: 2})", "Ok([['a',1],['b',2]])") testEvalToBe("Dict.fromList([['a', 1], ['b', 2]])", "Ok({a: 1,b: 2})") + testEvalToBe("Dict.map({a: 1, b: 2}, {|x| x * 2})", "Ok({a: 2,b: 4})") }) describe("Fn auto-testing", () => { diff --git a/packages/squiggle-lang/src/rescript/FR/FR_Dict.res b/packages/squiggle-lang/src/rescript/FR/FR_Dict.res index f0215faa4a..05319cc5a5 100644 --- a/packages/squiggle-lang/src/rescript/FR/FR_Dict.res +++ b/packages/squiggle-lang/src/rescript/FR/FR_Dict.res @@ -29,15 +29,49 @@ module Internals = { ->E.R2.fmap(Belt.Map.String.fromArray) ->E.R2.fmap(Wrappers.evRecord) + let set = (a: t, key, value): Reducer_T.value => IEvRecord(Belt.Map.String.set(a, key, value)) + //Belt.Map.String has a function for mergeMany, but I couldn't understand how to use it yet. let mergeMany = (a: array): Reducer_T.value => { let mergedValues = a->E.A.fmap(Belt.Map.String.toArray)->E.A.concatMany->Belt.Map.String.fromArray IEvRecord(mergedValues) } + + let map = ( + dict: t, + eLambdaValue, + context: Reducer_T.context, + reducer: Reducer_T.reducerFn, + ): Reducer_T.value => { + Belt.Map.String.map(dict, elem => + Reducer_Lambda.doLambdaCall(eLambdaValue, [elem], context, reducer) + )->Wrappers.evRecord + } } let library = [ + Function.make( + ~name="set", + ~nameSpace, + ~requiresNamespace=true, + ~output=EvtRecord, + ~examples=[`Dict.set({a: 1, b: 2}, "c", 3)`], + ~definitions=[ + FnDefinition.make( + ~name="set", + ~inputs=[FRTypeDict(FRTypeAny), FRTypeString, FRTypeAny], + ~run=(inputs, _, _) => { + switch inputs { + | [IEvRecord(dict), IEvString(key), value] => Internals.set(dict, key, value)->Ok + | _ => Error(impossibleError) + } + }, + (), + ), + ], + (), + ), Function.make( ~name="merge", ~nameSpace, @@ -170,4 +204,24 @@ let library = [ ], (), ), + Function.make( + ~name="map", + ~nameSpace, + ~requiresNamespace=true, + ~output=EvtRecord, + ~examples=[`Dict.map({a: 1, b: 2}, {|x| x + 1})`], + ~definitions=[ + FnDefinition.make( + ~name="map", + ~inputs=[FRTypeDict(FRTypeAny), FRTypeLambda], + ~run=(inputs, env, reducer) => + switch inputs { + | [IEvRecord(dict), IEvLambda(lambda)] => Ok(Internals.map(dict, lambda, env, reducer)) + | _ => Error(impossibleError) + }, + (), + ), + ], + (), + ), ]