Solving the "Mr.S and Mr.P" puzzle by John McCarthy: Formalization of two Puzzles Involving Knowledge McCarthy, John (1987). http://www-formal.stanford.edu/jmc/puzzles.html We pick two numbers a and b, so that a>=b and both numbers are within the range [2,99]. We give Mr.P the product a*b and give Mr.S the sum a+b. The following dialog takes place: Mr.P: I don't know the numbers Mr.S: I knew you didn't know. I don't know either. Mr.P: Now I know the numbers Mr.S: Now I know them too Can we find the numbers a and b? The following is a literate Haskell code. It can be loaded as it is in Hugs or GHCi. It takes a while to compute; the optimizations are straightforward; yet we deliberately chose the simplest code. A compiled version should be faster. Chung-chieh Shan has pointed out the paper Hans P. van Ditmarsch, Ji Ruan and Rineke Verbrugge Sum and Product in Dynamic Epistemic Logic Journal of Logic and Computation, 2008, v18, N4, pp.563--588. that discusses at great extent the history of the riddle, its modeling in modal `public announcement logic', and solving using epistemic model checkers. > module MrSP where First, let's define good numbers > good_nums = [2..99]::[Int] Given a number p, find all good factors a and b (a>=b) and return them (the pairs of them) in a list. We use the obvious and straightforward memoization (tabling): > good_factors_table = map gf [0..] > where > gf p = [ (a,b) | a<-good_nums, b<-good_nums, a >= b, a*b==p ] > good_factors p = good_factors_table !! p Given a number s, find all good summands a and b (a>=b) and return the pairs of them in a list > good_summands_table = map gs [0..] > where > gs s = [ (a,b) | a<-good_nums, b<-good_nums, a >= b, a+b==s ] > good_summands s = good_summands_table !! s > -- Test if a list is a singleton > singleton_p [_] = True > singleton_p _ = False Let's encode the first fact: Mr.P doesn't know the numbers. Mr. P would have known the numbers if the product had had a unique good factorization > fact1 (a,b) = not (singleton_p $ good_factors $ a*b) Let's encode the second fact: Mr.S doesn't know the numbers > fact2 (a,b) = not (singleton_p $ good_summands $ a+b) Let's encode the third fact: Mr.S knows that Mr.P doesn't know the numbers. In other words, for all possible summands that make a+b, Mr.P cannot be certain of the numbers > fact3 (a,b) = all fact1 (good_summands $ a+b) Let's encode the fourth fact: Mr.P _now_ knows that fact3 is true and is able to find the numbers. That is, of all factorizations of a*b there exists only one that makes fact3 being true. > fact4 (a,b) = singleton_p $ filter fact3 (good_factors $ a*b) The fifth fact is that Mr.S. knows that Mr.P found the numbers: of all the possible decompositions of a+b, there exists only one that makes fact4 true. > fact5 (a,b) = singleton_p $ filter fact4 (good_summands $ a+b) Finally, we compute the list of all numbers such that fact1..fact5 hold: > result = [(a,b) | a<-good_nums, b<-good_nums, a >= b, > all ($ (a,b)) [fact1,fact2,fact3,fact4,fact5] ] The answer is *Main> result [(13,4)] That is, a unique answer. Note how Haskell notation is concise, compared to the one employed in the paper by McCarthy.