(define (choices menu) (apply cartesian-product menu)) (choices (list '(small medium large) '(vanilla "ultra chocolate" lychee "rum raisin" ginger) '(cone cup)))]]>

cartesian [] = [] cartesian [x] = [[e] | e <- x] cartesian (x:xs) = [ x' : rest | x' <- x, rest <- cartesian xs ]

cartesian [] = [] cartesian [x] = map (e -> [e]) x cartesian (x:xs) = foldr (x' result -> (foldr (tc l -> (x':tc):l) result tailCross)) [] x where tailCross = cartesian xs]]>

fun cartesian [] = [] | cartesian ([x]) = map (fn e => [e]) x | cartesian (x::xs) = let val tailCross = cartesian xs in foldr (fn (x',result) => foldr (fn (tc,l) => (x'::tc) :: l ) result tailCross) [] x end]]>

fun cartesian ([x]) = map (fn e => [e]) x | cartesian (x::xs) = let val tailCross = cartesian xs in concat(map (fn e => map (fn e2 => e::e2) tailCross) x) end fun choices xs = map join (cartesian xs)

The Standard ML REPL abbreviated the list, but it works fine:

- choices [["Small","Medium", "Large"],["vanilla", "ultra chocolate", "lychee", "rum raisin", "ginger"],["cone", "cup"]]; val it = ["Small vanilla cone","Small vanilla cup","Small ultra chocolate cone", "Small ultra chocolate cup","Small lychee cone","Small lychee cup", "Small rum raisin cone","Small rum raisin cup","Small ginger cone", "Small ginger cup","Medium vanilla cone","Medium vanilla cup",...] : string list]]>

(use 'clojure.contrib.combinatorics) (def choices '(("small" "medium" "large") ("vanilla" "ultra chocolate" "lychee" "rum raisin" "ginger") ("cone" "cup"))) (doseq [x (apply cartesian-product choices)] (apply println x))]]>

(def choices '(("small" "medium" "large") ("vanilla" "ultra chocolate" "lychee" "rum raisin" "ginger") ("cone" "cup"))) (defn combo [l] (if (empty? (rest l)) (first l) (for [x (first l) y (combo (rest l))] (str x " " y)))) (doseq [x (combo choices)] (println x))]]>