type Nat = Integer (x # f) i = if i==0 then x else f (i-1) -- Borrowed from http://www.cs.bham.ac.uk/~mhe/papers/exhaustive.hs berger :: ((Nat -> Bool) -> Bool) -> (Nat -> Bool) berger p = let b0 = berger (\f -> p (False # f)) b1 = berger (\f -> p (True # f)) in if p (False # b0) then False # b0 else True # b1 -- As if by magic, isConst tests whether its argument is the -- constant function. isConst :: ((Nat -> Bool) -> Bool) -> Bool isConst p = let q f = p f /= pf pf = p (const False) in not (q (berger q)) data Tree = Tree Tree Tree | Leaf Bool deriving Show unmemo :: Tree -> (Nat -> Bool) -> Bool unmemo (Leaf x) a = x unmemo (Tree x y) a = unmemo (if a 0 then y else x) (a . (1+)) memo :: ((Nat -> Bool) -> Bool) -> Tree memo p = if isConst p then Leaf (p (const False)) else Tree (memo (p . (False #))) (memo (p . (True #))) -- id' converts a predicate on Boolean streams to a memoised version id' :: ((Nat -> Bool) -> Bool) -> ((Nat -> Bool) -> Bool) id' = unmemo . memo]]>

`pre`

tags. The preview button ought to show you how it comes out.
I don’t know what prevents the usual Markdown formatting from working in comments. More strangely yet, they *do* work for me but not for other folks.

For infinitely large domain values, we must then generate and follow infinite paths.

Actually, that’s not necessarily the case. A total function p of type Stream Bool -> Bool can only examine a finite number of elements of any stream argument it is given. Konig’s lemma tells us that for any p we can find a single finite number that bounds the number of stream elements that are ever examined, no matter what stream argument is given. This means we can use a finite trie for memoisation without doing lub tricks.

I’d post the code but don’t know what markup to use.

I’ll be checking out your lub posts in more detail. They answer some questions that have been nagging me for a while.

]]>When I wrote my blog article, I thought infinite lists couldn’t possibly be memoized. My argument was that in order to know you were looking at the right entry in the memo table you need equality on infinite lists.

Worse yet, (as you already know) in type-driven functional memoization, we don’t need to compare domain values for equality. Rather, we decode those values as paths into a type-based memo structure. For infinitely large domain values, we must then generate and follow infinite paths.

However, I think my posts on *Non-strict memoization* solve this problem, and can make memoization more efficient even with finite lists.
Don’t look (possibly forever) for “*the* right entry”.
Instead, given a (possibly infinite) domain value, combine the information (using `lub`

) associated with a chain of approximations leading up to the domain value in the limit.

For instance, consider memoizing the function that adds the first 20 elements of a list: `f = sum . take 20`

.
Using non-strict memoization, the work for all lists with the same first 20 elements can be shared, even for infinite lists.

When I wrote my blog article, I thought infinite lists couldn’t possibly be memoized. My argument was that in order to know you were looking at the right entry in the memo table you need equality on infinite lists. But equality on infinite lists isn’t computable.

However, that kind of informal reasoning tells you that this is impossible: http://math.andrej.com/2007/09/28/seemingly-impossible-functional-programs/

So now I’m not sure if infinite lists aren’t memoizable. From a topological perspective, the set of infinite lists are compact (in the appropriate topology) which means that they share many useful properties with finite sets. Memoizability may be one.

Seems like an nice problem to consider.

]]>