{-# LANGUAGE FlexibleInstances #-}
module Language.DSKanren.Sugar where
import Language.DSKanren.Core

-- | Disjunction of many clauses. This can be thought as a logical
-- switch.
conde :: [Predicate] -> Predicate
conde = foldr disconj failure

-- | Conjuction of many clauses. Think of this as a sort of logical
-- semicolon.
program :: [Predicate] -> Predicate
program = foldr conj success

-- | Only grab n solutions. Useful for when the full logic program
-- might not terminate. Or takes its sweet time to do so.
runN :: Int -> (Term -> Predicate) -> [(Term, [Neq])]
runN n = take n . run

-- | We often want to introduce many fresh variables at once. We've
-- encoded this in DSKanren with the usual type class hackery for
-- variadic functions.
class MkFresh a where
  -- | Instantiate @a@ with as many fresh terms as needed to produce a
  -- predicate.
  manyFresh :: a -> Predicate
instance MkFresh a => MkFresh (Term -> a) where
  manyFresh = fresh . fmap manyFresh
instance MkFresh Predicate where
  manyFresh = id

-- | Build a lispish list out of terms. The atom @"nil"@ will serve as
-- the empty list and 'Pair' will be ':'.
list :: [Term] -> Term
list = foldr Pair (Atom "nil")