Hey all, I come with a logic programming question, hopefully it is on topic since I am using typedKanren .
I tried to write a hasLength :: forall a . Logical a => Term [a] -> Term Binary -> Goal ()
predicate that relates an arbitrary list to its length. The problem is am not able to make it bidirectional.
I have two implementations, the only difference between them is the order of the last two clauses. Each works in one direction, but none works in both directions:
-- A simple datatype for the example
data Color = R | G | B
deriving stock (Eq, Show, Generic)
makeLogicals [''Color]
deriving stock instance Show LogicColor
-- The predicate
hasLength :: forall a. Logical a => Term Binary -> Term [a] -> Goal ()
hasLength n ls =
disj
do
zeroo n
ls & isNil
do
(n', t) <- fresh;
-- Implementation 1:
ls & hasTail t; t & hasLength n';
addo n' (inject' 1) n
-- Implementation 2:
addo n' (inject' 1) n
ls & hasTail t; t & hasLength n';
-- One query for each possible direction
queryList :: IO ()
queryList = mapM_ print $ run $ \(ls :: Term [Color]) -> ls & hasLength (inject' 3)
queryLength :: IO ()
queryLength = mapM_ print $ run $ \n -> inject' [R, G, B] & hasLength n
And if I test the queries in ghci, these are the results:
Implementation 1:
ghci> queryList
[_.4,_.9,_.14]
^CInterrupted.
ghci> queryLength
[I,I]
ghci>
Implementation 2:
ghci> queryList
[_.23,_.30,_.37]
ghci> queryLength
[I,I]
^CInterrupted.
ghci>
So, how can I write an implementation that works for both queries? Is it possible?