Fork me on GitHub
#core-logic
<
2022-01-24
>
Adrian Sci16:01:08

I am writing a function to remove a list of elements from another list. So given a list of elements to be removed [a c] and the list to remove it from [c b d a e] I want to run rembero twice on the list and have it return [b d e]. I have written a pretty messy recursion and it seems to work. However when I am scaling up the rest of my program I start to get a stack overflow and I think this recursion could be one of the pain points. Does anyone have any advice on a better way of doing this?

;;recursion to remove a list of inputs from the world state
(defn rembero-all [lst state temp]
    (conde
    [(== lst ())
     (== state temp)]
    [(fresh [fst rst rectemp]
        (conso fst rst lst)
        (rembero fst state temp)
        (rembero-all rst temp rectemp))]))

paulocuneo19:01:51

Hi! I would write something like this (dunno if this impl is correct 😆), not for performance but in my opinion is more readable. Be ware that pattern matching (matche defne ) shadows local variable names.

;;modified from rembero implementation
(defne rembero-all
  "relation where `o` is the result of removing all occurrences of `x` from `l`"
  [x l o]
  ([_ [] []])
  ([_ [y] []] ;; edited
   (== x y))
  ([_ [y . ys] [z . zs]] ;; edited
   (== x y)
   (!= x z)
   (rembero-all x ys o))
  ([_ [y . ys] [y . zs]]
   (!= y x)
   (rembero-all x ys zs)))

(defne rembero-many
  "relation where `o` is result of removing all items `xs` from `l`"
 [xxs l o]
 ([_  [] []])
 ([[] ys ys])
 ([[x . xs]  _ _]
  (fresh [l']
    (rembero-all x l l')
    (rembero-many xs l' o))))

(run 1 [q]
  (rembero-many [1 2 3] [1 4 2 5 3 7 1 8 2 9 3] q))
Sorry, I can't help with performance 😅