module Lis where infixr `cons'` infixr `cons''` infixr `cons'''` -- basic implementation: forlist fnil fcons ls = ls fnil fcons cons x xs fnil fcons = fcons x xs nil fnil fcons = fnil {- "most general type" version: -} forlist' = forlist cons' = cons nil' = nil -- passes: tail' = forlist' undefined (\x xs -> xs) -- doesn't pass: -- map' f = forlist' nil' (\x xs -> f x `cons'` map' f xs) {- typed version with two type variables: the first being the list element type, the second being the result type of the function that is constructed with forlist. Enforces ls and (tail ls) to have the same type: -} newtype List'' a b = L'' (b -> (a -> List'' a b -> b) -> b) forlist'' fnil fcons (L'' ls) = forlist fnil fcons ls nil'' = L'' nil cons'' x xs = L'' $ cons x xs -- passes: map'' f = forlist'' nil'' (\x xs -> f x `cons''` map'' f xs) -- doesn't pass: -- tail'' = forlist'' undefined (\x xs -> xs) -- passes at the cost of copying the whole result: repaired_tail'' = forlist'' undefined (\x xs -> map'' id xs) {- typed version with three type variables: the first being list element type, the second being the result type of the function which is constructed with forlist, the third being the result type of the function which consumes the list. Enforces (tail ls) and (tail (tail ls)) to have the same type: -} newtype List''' a b c = L''' (b -> (a -> List''' a c c -> b) -> b) forlist''' fnil fcons (L''' ls) = forlist fnil fcons ls nil''' = L''' nil cons''' x xs = L''' $ cons x xs -- passes again: map''' f = forlist''' nil''' (\x xs -> f x `cons'''` map''' f xs) -- now passes: tail''' = forlist''' undefined (\x xs -> xs) -- doesn't pass: -- tailtail''' ls = tail''' (tail''' ls)