package com.acme.adt; import static com.acme.adt.LinkedList.List.*; @SuppressWarnings("unchecked") public class LinkedList { public abstract static class List<T> { public interface Visitor<T, S> { default S get(List<T> receiver) { S result = receiver.accept(this); return result == null ? defaultImplementation(receiver) : result; } default S getOrDefault(List<T> receiver, S defaultValue) { S result = receiver.accept(this); return result == null ? defaultValue : result; } default S nil() { return null; } default S cons(T first, List<T> rest) { return null; } default S defaultImplementation(List<T> e) { throw new UnsupportedOperationException(); } } public abstract <S> S accept(Visitor<T, S> visitor); public static <T> List<T> nil() { return new List<T>() { public <S> S accept(Visitor<T, S> visitor) { return visitor.nil(); } }; } public static <T> List<T> cons(T first, List<T> rest) { return new List<T>() { public <S> S accept(Visitor<T, S> visitor) { return visitor.cons(first, rest); } }; } } public static <T> int length1(List<T> $0) { return new List.Visitor<T, Integer>() { public Integer nil() { return 0; } public Integer cons(T first, List<T> rest) { return (1 + LinkedList.length1(rest)); } } .get($0); } public static <T> int length2(List<T> l) { return new List.Visitor<T, Integer>() { public Integer nil() { return 0; } public Integer cons(T first, List<T> rest) { return (1 + LinkedList.length2(rest)); } } .get(l); } public static void main(String[] args) { List<Integer> l = cons(1, cons(2, nil())); assert length1(l) == 2; assert length2(l) == 2; } }