A friend was messing about with the `amb`

operator in JavaScript after seeing it in Common Lisp. The `amb`

(or *ambiguous*) operator, first described by our pal John McCarthy (1967), and something I first encountered in SICP.

These kind of constraint/logic puzzles seem naturally solved by the list monad, here’s an example of solving ‘Who owns the fish?’ Similar to the Zebra puzzle.

-- Translation of -- http://mihai.bazon.net/blog/amb-in-javascript/take-two#wotf import Control.Monad import Data.Maybe import Data.List whoOwnsTheFish = addHouse [] addHouse houses = do nat <- other "nat" ["British","Swedish","Danish","Norwegian" ,"German"] col <- other "col" ["red","green","white","yellow","blue"] pet <- other "pet" ["dogs","cats","horses","birds","fish"] bev <- other "bev" ["tea","milk","coffee","beer","water"] tob <- other "tob" ["pallmall","dunhill","marlboro" ,"winfield","rothmans"] (nat == "British") `iff` (col == "red") (nat == "Swedish") `iff` (pet == "dogs") (nat == "Danish") `iff` (bev == "tea") (col == "white") `iff` (thisHouse > 0 && "col" `lookup` (houses!!(thisHouse - 1)) == Just "green") (col == "green") `iff` (bev == "coffee") (tob == "pallmall") `iff` (pet == "birds") (col == "yellow") `iff` (tob == "dunhill") (thisHouse == 2) `iff` (bev == "milk") (thisHouse == 0) `iff` (nat == "Norwegian") (tob == "winfield") `iff` (bev == "beer") (nat == "German") `iff` (tob == "rothmans") let h = [("nat",nat),("bev",bev),("tob",tob),("pet",pet) ,("col",col)] a = houses ++ [h] if length a == 5 then do neighbors a "tob" "marlboro" "pet" "cats" neighbors a "pet" "horses" "tob" "dunhill" neighbors a "nat" "Norwegian" "col" "blue" neighbors a "tob" "marlboro" "bev" "water" return a else addHouse a where other typ = filter (isNothing . findHouse houses typ) thisHouse = length houses findHouse houses typ val = fmap fst . find ((==Just val) . lookup typ . snd) . zip [0..] $ houses neighbors houses typ1 val1 typ2 val2 = guard $ diff == Just 1 where diff = do h1 <- findHouse houses typ1 val1 h2 <- findHouse houses typ2 val2 return $ abs $ h1 - h2 iff x y = guard $ x == y