From 7f38e74e781aaa78f8bc21ce0644fd501cc51807 Mon Sep 17 00:00:00 2001
From: MadMaurice <madmaurice@zom.bi>
Date: Fri, 2 Apr 2021 20:18:42 +0200
Subject: [PATCH] Add map, reduce and equal for lists

---
 lib/Minilisp.pm | 22 ++++++++++++++++++++++
 t/lists.t       |  4 ++++
 2 files changed, 26 insertions(+)

diff --git a/lib/Minilisp.pm b/lib/Minilisp.pm
index 72fbc6f..b3133fb 100644
--- a/lib/Minilisp.pm
+++ b/lib/Minilisp.pm
@@ -229,6 +229,28 @@ my %stdctx = (
   'first' => sub { return (shift)->[0]; },
   'second' => sub { return (shift)->[1]; },
   'nth' => sub { my ($idx,$list) = @_; return $list->[$idx]; },
+  'map' => sub {
+    my ($cb,$list) = @_;
+    die "map: First parameter must be a function" unless ref($cb) eq "CODE";
+    die "map: Second parameter must be a list" unless ref($list) eq "ARRAY";
+
+    return [ map { $cb->($_) } @$list ];
+  },
+  'reduce' => sub {
+    my ($cb,$list) = @_;
+    die "map: First parameter must be a function" unless ref($cb) eq "CODE";
+    die "map: Second parameter must be a list" unless ref($list) eq "ARRAY";
+
+    my @copy = ( @$list );
+    my $v = shift @copy;
+    $v = $cb->($v,$_) foreach (@copy);
+    return $v;
+  },
+  # TODO: this is tricky as it needs to recurse into sub lists
+  'equal' => sub {
+    my ($a, $b) = @_;
+    return @$a == @$b;
+  },
 
   # Constants
   't' => 1,
diff --git a/t/lists.t b/t/lists.t
index 80d9194..b079959 100644
--- a/t/lists.t
+++ b/t/lists.t
@@ -4,4 +4,8 @@
   (expect "First element is 1" (= (first lst) 1))
   (expect "Second element is 2" (= (second lst) 2))
   (expect "Third element is 3" (= (nth 2 lst) 3))
+  (expect "Equal to itself" (equal lst lst))
+  (expect "Equal to identical list" (equal lst (list 1 2 3)))
+  (expect "Reduce with +" (= (reduce + lst) 6))
+  (expect "Map doubling values" (equal (map (lambda (x) (* x 2)) lst) (list 2 4 6)))
   )