001package visitor.list;
002
003/* public */
004interface List {
005        public <T> T accept(ListVisitor<T> v);
006}
007
008/* public */
009class ListF {
010        private ListF() {}
011        public static final List nil = new Nil(); /* Singleton */
012        public static final List cons(int hd, List tl) /* Factory */ {
013                return new Cons(hd, tl);
014        }
015}
016
017/* public */
018interface ListVisitor<T> {
019        public T visitNil();
020        public T visitCons(int hd, List tl);
021}
022
023/*
024 *************************************************************************
025 * List classes.
026 *************************************************************************
027 */
028class Nil implements List {
029        Nil() {}
030        public String toString() { return "nil"; }
031        public <T> T accept(ListVisitor<T> v) {
032                return v.visitNil();
033        }
034}
035
036class Cons implements List {
037        private final int hd;
038        private final List tl;
039        Cons(int hd, List tl) { this.hd = hd; this.tl = tl; }
040        public String toString() { return hd + "::" + tl.toString(); }
041        public <T> T accept(ListVisitor<T> v) {
042                return v.visitCons(hd, tl);
043        }
044}
045
046/*
047 *************************************************************************
048 * Visitor classes.
049 * The visitor to a Cons is responsible for visiting the tl.
050 *************************************************************************
051 */
052class Sum implements ListVisitor<Integer> {
053        public Integer visitNil() { return 0; }
054        public Integer visitCons(int hd, List tl) {
055                return hd + tl.accept(this);
056        }
057}
058
059class Reverse implements ListVisitor<List> {
060        private List result = ListF.nil; // use a field to accumulate the value
061        public List visitNil() { return result; }
062        public List visitCons(int hd, List tl) {
063                result = ListF.cons(hd, result);
064                return tl.accept(this);
065        }
066}
067
068/*
069 *************************************************************************
070 * A test case.
071 *************************************************************************
072 */
073public class Main {
074        public static void main(String[] args) {
075                List test = ListF.cons(1, ListF.cons(2, ListF.cons(3, ListF.nil)));
076                System.out.println(test);
077
078                System.out.println(test.accept(new Sum()));
079
080                System.out.println(test.accept(new Reverse()));
081        }
082}
083
084
085/*
086 *************************************************************************
087 * Here is the corresponding SML code.
088 * It is intended to match the Java as closely as possible.
089 *************************************************************************
090datatype List = Nil | Cons of int * List
091
092fun toString (this : List) : string =
093    case this of
094        Nil => "nil"
095      | Cons(hd, tl) => Int.toString(hd) ^ "::" ^ toString(tl)
096
097fun sum (acceptor : List) : int =
098    case acceptor of
099        Nil => 0
100      | Cons(hd, tl) => hd + sum(tl)
101
102fun reverse (acceptor : List) : List =
103    let fun reverseAux (acceptor : List, result : List) =
104            case acceptor of
105                Nil => result
106              | Cons(hd, tl) => reverseAux(tl, Cons(hd,result))
107    in
108        reverseAux (acceptor, Nil)
109    end
110
111fun main () : unit =
112    let
113        val testList = Cons(1, Cons(2, Cons(3, Nil)))
114        val  = print(toString(testList) ^ "\n")
115        val  = print(Int.toString(sum(testList)) ^ "\n")
116        val  = print(toString(copy(testList)) ^ "\n")
117        val  = print(toString(reverse(testList)) ^ "\n")
118    in
119        ()
120    end
121
122 *************************************************************************
123 */