From 85b907da943719942d68258c97823df846b549db Mon Sep 17 00:00:00 2001 From: Lexy Plateau Date: Thu, 27 Aug 2026 14:10:17 +0200 Subject: [PATCH 1/4] test(dict): use @ as well as dict:get to get an item from a dict --- tests/dict-tests.ark | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/dict-tests.ark b/tests/dict-tests.ark index be65acd..597c0c1 100644 --- a/tests/dict-tests.ark +++ b/tests/dict-tests.ark @@ -39,13 +39,20 @@ (test:neq d3 d2) (test:neq d3 d4) }) - (test:case "get" { + (test:case "get, @" { (test:eq (dict:get d "key") "value") (test:eq (dict:get d 5) 12) (test:eq (dict:get d true) true) (test:eq (dict:get d false) false) (test:eq (dict:get d foo) "yes") - (test:eq (dict:get d closure) foo) }) + (test:eq (dict:get d closure) foo) + + (test:eq (@ d "key") "value") + (test:eq (@ d 5) 12) + (test:eq (@ d true) true) + (test:eq (@ d false) false) + (test:eq (@ d foo) "yes") + (test:eq (@ d closure) foo) }) (test:case "getOrElse" { (test:eq (dict:getOrElse d "key" 5) "value") From 0e67371c15629ca30616ebd4612161b0308354db Mon Sep 17 00:00:00 2001 From: Lexy Plateau Date: Sat, 29 Aug 2026 13:15:23 +0200 Subject: [PATCH 2/4] feat(dict): @= now works on dict and behaves like dict:add --- tests/dict-tests.ark | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/dict-tests.ark b/tests/dict-tests.ark index 597c0c1..349fe14 100644 --- a/tests/dict-tests.ark +++ b/tests/dict-tests.ark @@ -93,14 +93,21 @@ (test:eq (dict:fromList (dict:entries d)) d) (test:eq (dict:fromList [["a" 1]]) (dict "a" 1)) }) - (test:case "add" { + (test:case "add, @=" { (test:eq (dict:get d "test") nil) (dict:add d "test" 5) (test:eq (dict:get d "test") 5) (test:eq (dict:get d "key") "value") (dict:add d "key" 2) - (test:eq (dict:get d "key") 2) }) + (test:eq (dict:get d "key") 2) + + (mut d_add (dict)) + (test:eq d_add empty) + (@= d_add 1 2) + (test:eq (dict:get d_add 1) 2) + (@= d_add 1 4) + (test:eq (dict:get d_add 1) 4) }) (test:case "updateOrDefault" { (let d5 (dict)) From 9006708a2f542cd87d2e1a0185e24186691de409 Mon Sep 17 00:00:00 2001 From: Lexy Plateau Date: Tue, 29 Sep 2026 18:43:26 +0200 Subject: [PATCH 3/4] feat(list): ARK-384 add foldRight, and alias list:fold to list:foldLeft --- List.ark | 56 +++++++++++++++++++++++++++++++++++++++----- tests/list-tests.ark | 10 +++++++- 2 files changed, 59 insertions(+), 7 deletions(-) diff --git a/List.ark b/List.ark index 15505ca..ee5ec07 100644 --- a/List.ark +++ b/List.ark @@ -558,10 +558,10 @@ # @details The original list is not modified. # =begin # (let a [1 2 3 4]) -# (print (list:foldLeft a 0 (fun (a b) (+ a b)))) # 10 +# (print (list:fold a 0 (fun (a b) (+ a b)))) # 10 # =end # @author https://github.com/SuperFola -(let foldLeft (fun ((ref _L) _init _f) { +(let fold (fun ((ref _L) _init _f) { (mut _index 0) (mut _val _init) @@ -570,6 +570,38 @@ (set _index (+ 1 _index)) }) _val })) +# @brief Fold a given list, starting from the left side +# @param _L the list to work on +# @param _init an init value +# @param _f a function to apply to the list +# @details The original list is not modified. +# =begin +# (let a [1 2 3 4]) +# (print (list:foldLeft a 0 (fun (a b) (+ a b)))) # 10 +# =end +# @author https://github.com/SuperFola +(let foldLeft fold) + +# @brief Fold a given list, starting from the right side +# @param _L the list to work on +# @param _init an init value +# @param _f a function to apply to the list +# @details The original list is not modified. +# =begin +# (let a [1 2 3 4]) +# (print (list:foldRight a 0 (fun (a b) (+ a b)))) # 10 +# =end +# @author https://github.com/SuperFola +(let foldRight (fun ((ref _L) _init _f) { + (mut _index 0) + (mut _val _init) + (let _limit (len _L)) + + (while (< _index _limit) { + (set _val (_f _val (@ _L (- _limit _index 1)))) + (set _index (+ 1 _index)) }) + _val })) + # @brief Apply a function to the elements of a list to reduce it # @param _L the list to work on # @param _f the function to apply @@ -1167,8 +1199,14 @@ # =end # @author https://github.com/SuperFola (let intersection (fun ((ref _L1) (ref _L2)) { - (mut _target (if (> (len _L2) (len _L1)) _L1 _L2)) - (let _iterate (if (> (len _L2) (len _L1)) _L2 _L1)) + (mut _target + (if (> (len _L2) (len _L1)) + _L1 + _L2)) + (let _iterate + (if (> (len _L2) (len _L1)) + _L2 + _L1)) (mut _i 0) (mut _output []) @@ -1198,8 +1236,14 @@ # =end # @author https://github.com/SuperFola (let difference (fun ((ref _L1) (ref _L2)) { - (mut _target (if (> (len _L2) (len _L1)) _L1 _L2)) - (let _iterate (if (> (len _L2) (len _L1)) _L2 _L1)) + (mut _target + (if (> (len _L2) (len _L1)) + _L1 + _L2)) + (let _iterate + (if (> (len _L2) (len _L1)) + _L2 + _L1)) (mut _i 0) (mut _output []) diff --git a/tests/list-tests.ark b/tests/list-tests.ark index afebd3a..c621f2c 100644 --- a/tests/list-tests.ark +++ b/tests/list-tests.ark @@ -283,11 +283,19 @@ (test:eq (list:zipLongest a [4 5] nil) [[1 4] [2 5] [3 nil]]) (test:eq (list:zipLongest [] [] nil) []) }) - (test:case "foldLeft" { + (test:case "fold, foldLeft" { + (test:eq (list:fold [] 0 (fun (x y) (+ x y))) 0) (test:eq (list:foldLeft [] 0 (fun (x y) (+ x y))) 0) + (test:eq (list:fold ["1" "2" "3"] "" (fun (x y) (+ x y))) "123") (test:eq (list:foldLeft ["1" "2" "3"] "" (fun (x y) (+ x y))) "123") + (test:eq (list:fold a 0 (fun (x y) (+ x y))) 6) (test:eq (list:foldLeft a 0 (fun (x y) (+ x y))) 6) }) + (test:case "foldRight" { + (test:eq (list:foldRight [] 0 (fun (x y) (+ x y))) 0) + (test:eq (list:foldRight ["1" "2" "3"] "" (fun (x y) (+ x y))) "321") + (test:eq (list:foldRight a 0 (fun (x y) (+ x y))) 6) }) + (test:case "zipWithIndex" { (test:eq (list:zipWithIndex a) [[0 1] [1 2] [2 3]]) (test:eq (list:zipWithIndex []) []) }) From 7c3877260f4bb669d2fbd7ceeaab0f5945c60bc9 Mon Sep 17 00:00:00 2001 From: Lexy Plateau Date: Sun, 11 Oct 2026 14:01:16 +0200 Subject: [PATCH 4/4] feat(macros): ARK-387 add fun-> and some-> macros --- Macros.ark | 59 +++++++++++++++++++++++++++++++++++++++--- tests/macros-tests.ark | 25 ++++++++++++++++++ 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/Macros.ark b/Macros.ark index 231b2b1..a1c07c9 100644 --- a/Macros.ark +++ b/Macros.ark @@ -23,13 +23,66 @@ # =end # @author https://github.com/SuperFola (macro -> (arg fn1 ...fns) { - ($if (= "Symbol" ($type fn1)) - (macro call (fn1 arg)) - (macro call ((__replace_all_placeholders_with arg ...fn1)))) + (macro call ($if (= "Symbol" ($type fn1)) + (fn1 arg) + ((__replace_all_placeholders_with arg ...fn1)))) ($if (> ($len fns) 0) (-> call ...fns) call) }) +# internal, do not use +(macro __some-> (tmp val fn1 ...fns) { + (macro call ($if (= "Symbol" ($type fn1)) + (fn1 tmp) + ((__replace_all_placeholders_with tmp ...fn1)))) + + (mut tmp val) + (if (not (nil? tmp)) + { + ($if (> ($len fns) 0) + (__some-> tmp call ...fns) + (set tmp call)) }) }) + +# @brief Threading with nil short-circuiting. If any step produces nil, the chain stops and returns the nil value. +# @param arg value to transform +# @param ...fns series of functions to apply one by one to `arg` +# =begin +# (import std.Macros) +# (mut db (dict +# "tables" (dict +# "users" (dict +# "lexy" "dev")))) +# (print (some-> db +# (@ _ "tables") +# (@ _ "users") +# (@ _ "lexy"))) +# # "dev" +# (print (some-> nil)) # nil +# (print (some-> (dict "tables" nil))) # nil +# =end +# @author https://github.com/SuperFola +(macro some-> (arg fn1 ...fns) { + { + (macro tmp ($gensym)) + (__some-> tmp arg fn1 ...fns) + tmp } }) + +# @brief Represent a pipeline of calls as a function +# @param ...fns series of functions to apply one by one to `arg` +# =begin +# (import std.Macros) +# # equivalent to (f1 "f0") +# (let a (fun-> f1)) (a "f0") +# # equivalent to (f3 (f2 (f1 "f0"))) +# (let b (fun-> f1 f2 f3)) (b "f0") +# # equivalent to (bar (foo (f1 "f0") f2) f3) +# (let c (fun-> f1 (foo _ f2) (bar _ f3))) (c "f0") +# =end +# @author https://github.com/SuperFola +(macro fun-> (fn1 ...fns) { + (macro arg ($gensym)) + (fun (arg) (-> arg fn1 ...fns)) }) + # internal, do not use (macro __suffix-dup (sym x) { ($if (> x 1) (__suffix-dup sym (- x 1))) diff --git a/tests/macros-tests.ark b/tests/macros-tests.ark index da06530..6f2d36c 100644 --- a/tests/macros-tests.ark +++ b/tests/macros-tests.ark @@ -15,6 +15,15 @@ (let test_func2 (partial test_func1 2)) (let test_func3 (partial2 test_func 1 _ 3)) (let test_func4 (partial2 test_func _ 2 _)) +(let db (dict + "tables" (dict + "users" (dict + "lexy" "dev")))) +(let db2 (dict + "tables" (dict + "users" nil))) +(let db3 (dict + "tables" nil)) (test:suite macros { (test:case "->" { @@ -22,6 +31,22 @@ (test:eq (-> "f0" f1 f2 f3) "f0-f1-f2-f3") (test:eq (-> "f0" f1 (foo _ f2) (foo _ f3)) "f0-f1-f2-f3") }) + (test:case "some->" { + (test:eq (some-> db (@ _ "tables") (@ _ "users") (@ _ "lexy")) "dev") + (test:eq (some-> db2 (@ _ "tables") (@ _ "users") (@ _ "lexy")) nil) + (test:eq (some-> db3 (@ _ "tables") (@ _ "users") (@ _ "lexy")) nil) + (test:eq (some-> nil (@ _ "tables") (@ _ "users") (@ _ "lexy")) nil) }) + + (test:case "fun->" { + (mut fun_thread (fun-> f1)) + (test:eq (fun_thread "f0") "f0-f1") + + (mut fun_thread (fun-> f1 f2 f3)) + (test:eq (fun_thread "f0") "f0-f1-f2-f3") + + (mut fun_thread (fun-> f1 (foo _ f2) (foo _ f3))) + (test:eq (fun_thread "f0") "f0-f1-f2-f3") }) + (test:case "partial & partial2" { (test:eq (test_func1 2 3) 6) (test:eq ($argcount test_func1) 2)