@@ -686,6 +686,131 @@ const put = operation_table("insert");
686
686
</SPLITINLINE >
687
687
should take as input a list of keys used to access the table.
688
688
<LABEL NAME =" ex:3_25" />
689
+ <SOLUTION >
690
+ <SNIPPET >
691
+ <NAME >solution_3_25</NAME >
692
+ <EXAMPLE >solution_3_25_example</EXAMPLE >
693
+ <JAVASCRIPT >
694
+ // contributed by GitHub user tttinkl
695
+
696
+ function assoc(key, records, same_key) {
697
+ return is_null(records)
698
+ ? undefined
699
+ : same_key(key, head(head(records)))
700
+ ? head(records)
701
+ : assoc(key, tail(records), same_key);
702
+ }
703
+
704
+
705
+ function make_table(same_key) {
706
+ const local_table = list("*table");
707
+
708
+ const get_value = tail;
709
+
710
+ function is_table(t) {
711
+ return is_pair(t) && head(t) === "*table";
712
+ }
713
+
714
+ function lookup(keys) {
715
+ function lookup_generic(keys, table) {
716
+ if (is_null(keys)) {
717
+ return table;
718
+ }
719
+ const key_1 = head(keys);
720
+ const key_rest = tail(keys);
721
+ const record = assoc(key_1, tail(table), same_key);
722
+ if (is_undefined(record)) {
723
+ return undefined;
724
+ }
725
+ if (is_null(key_rest)) {
726
+ return get_value(record);
727
+ } else if (is_table(get_value(record))) {
728
+ return lookup_generic(key_rest, get_value(record));
729
+ } else {
730
+ error('invalid key');
731
+ }
732
+ }
733
+ return lookup_generic(keys, local_table);
734
+ }
735
+
736
+
737
+ function insert(keys, value) {
738
+ function insert_generic(keys, value, table) {
739
+ const key_1 = head(keys);
740
+ const key_rest = tail(keys);
741
+ const record = assoc(key_1, tail(table), same_key);
742
+ if (is_undefined(record)) {
743
+ if (is_null(key_rest)) {
744
+ set_tail(
745
+ table,
746
+ pair(pair(key_1, value), tail(table)));
747
+ } else {
748
+ const new_subtable = list("*table");
749
+ set_tail(
750
+ table,
751
+ pair(pair(key_1, new_subtable), tail(table))
752
+ );
753
+ insert_generic(key_rest, value, new_subtable);
754
+ }
755
+ } else {
756
+ if (is_null(key_rest)) {
757
+ set_tail(record, value);
758
+ } else {
759
+ if (is_table(get_value(record))) {
760
+ insert_generic(key_rest, value, get_value(record));
761
+ } else {
762
+ const new_subtable = list("*table");
763
+ set_tail(record, new_subtable);
764
+ insert_generic(key_rest, value, new_subtable);
765
+ }
766
+ }
767
+ }
768
+ }
769
+ insert_generic(keys, value, local_table);
770
+ }
771
+
772
+ function dispatch(m) {
773
+ return m === "lookup"
774
+ ? lookup
775
+ : m === "insert"
776
+ ? insert
777
+ : m === "show"
778
+ ? () => {
779
+ display(local_table);
780
+ return local_table;
781
+ }
782
+ : error(m, "unknow operation -- table");
783
+ }
784
+ return dispatch;
785
+ }
786
+
787
+ const table = make_table(equal);
788
+
789
+ const get = table('lookup');
790
+ const put = table('insert');
791
+ const show = table('show');
792
+ </JAVASCRIPT >
793
+ </SNIPPET >
794
+ <SNIPPET HIDE =" yes" >
795
+ <NAME >solution_3_25_example</NAME >
796
+ <JAVASCRIPT >
797
+ put(list("a"), 1);
798
+ put(list("b", "c"), 2);
799
+ put(list("d", "e", "f"), 3);
800
+
801
+ display(get(list("a")));
802
+ display(get(list("b", "c")));
803
+ display(get(list("d", "e", "f")));
804
+
805
+ put(list("a", "b"), 1);
806
+ display(get(list("a")));
807
+ put(list("b", "c", "d"), 2);
808
+ display(get(list("b", "c")));
809
+ put(list("b"), 1);
810
+ display(get(list("b")));
811
+ </JAVASCRIPT >
812
+ </SNIPPET >
813
+ </SOLUTION >
689
814
</EXERCISE >
690
815
691
816
<EXERCISE >
0 commit comments