I need some #lisp help.
I'm stuck on a recursion exercise - have been for 2 days!
We're given a at a structure a list of lists, where each such list is of the form (person mother father) .. and so a lot of these together create a family tree.
I want to write a function lineage x y which returns a list of ancestors from x to y ... eg x, mother of x, father of prev, y .... or NIL if y is not an ancestor of x.
I found this easy in #prolog (I wrote this prologbyexample.blogspot.com/2… ) but not #lisp.
7 - Introducing Recursion
Recursion is an important technique in many programming languages, especially declarative languages like prolog. It enables elegant and ...prologbyexample.blogspot.com
This entry was edited (3 weeks ago)
screwlisp
Unknown parent • • •Sensitive content
oh, I didn't even get it. Only works in :program mode ;p
Alexander Burger
in reply to Tariq • • •In #PicoLisp it could be pb1n.de/?c3be0c
#Lisp
screwlisp
in reply to Alexander Burger • • •Sensitive content
(defun repeatedly-removes (a b f)
(declare (xargs :measure (len f)))
(if (zp (len f)) nil
(let ((person (assoc a f)))
(if (member b (cdr person)) person
(let ((new-f (remove person f)))
(if (< (len new-f) (len f))
(or
(repeatedly-removes (cadr person) b new-f)
(repeatedly-removes (caddr person) b new-f))
nil))))))
Phew, that was a memory and a half
screwlisp reshared this.
Jencel Panic
in reply to screwlisp • • •Sensitive content
screwlisp
in reply to Jencel Panic • • •Sensitive content
On the other hand, Haskell is not a first order logic I guess.
@Regenaxer @rzeta0
Jencel Panic
in reply to screwlisp • • •Sensitive content
screwlisp
in reply to Jencel Panic • • •Sensitive content
When you say the type thing, we are kinda talking about Curry-Howard correspondence en.wikipedia.org/wiki/Curry%E2… right? Though ACL2 (which I think is strongly typed via often-implicit guards) goes the route of specifically being a first order logic with automatic proof attempts.
@Regenaxer @rzeta0
the direct relationship between computer programs and mathematical proofs
Contributors to Wikimedia projects (Wikimedia Foundation, Inc.)Jencel Panic
in reply to screwlisp • • •Sensitive content
screwlisp
in reply to Jencel Panic • • •Sensitive content
@abuseofnotation
You're right of course, a first order logic automatic theorem prover and haskell were not particularly similar.
Did you check out any of gopher.someodd.zip's haskell (after the interview today)? github.com/someodd/burrow
@Regenaxer @rzeta0
GitHub - someodd/burrow: Static gopherhole generator.
GitHubJencel Panic
in reply to screwlisp • • •Sensitive content
screwlisp
in reply to Jencel Panic • • •Sensitive content
only in that someodd also programs in Haskell (for about seven years now) and was on the show today.
@Regenaxer @rzeta0
Jencel Panic
in reply to screwlisp • • •Sensitive content
@screwtape @Regenaxer
Haskell solution 😀
Not sure if I should use an accumulator, but I think it is good, as it allow you to split the function to more manageable bits.
gist.github.com/abuseofnotatio…
recursion-exercise.hs
Gistscrewlisp reshared this.
screwlisp
Unknown parent • • •Sensitive content
If we can both pretend I didn't just use a javascript haskell compiler play.haskell.org/saved/BPJkVGq…
But I found that your one returns the whole matrilineal ancestry on failure, so I guess we also need to compare the last ancestor found with the name we were looking for.
It's interesting to compare my eventual :logic success mastodon.sdf.org/@screwtape/11… in ACL2 to Haskell, since they're both famously formal, however acl2 is specifically first order logic.
@Regenaxer @rzeta0
screwlisp
2025-03-17 10:13:19
screwlisp reshared this.
Jencel Panic
in reply to Jencel Panic • • •Sensitive content
screwlisp
in reply to screwlisp • • •Sensitive content
@me @jeremy_list you're both lisp and Haskell programmers, how would you do it?
@abuseofnotation @Regenaxer @rzeta0
Tariq
in reply to Tariq • • •here is a portion of of the data structure:
(defvar family
'((linda nil nil)
(suzanne colin deirdre)
(bruce arthur kate)
(charles arthur kate)
(david arthur kate)
(ellen arthur kate)
(george frank linda)
(hillary frank linda)
(andre nil nil) ...
Riley S. Faelan
in reply to Tariq • • •Beware that if you're always doing list scans, your complexity can really blow up. Once you will have solved the problem in the classic Lisp style, you might also want to look into implementing it using a hash table. (These are part of the Common Lisp standard library.)
And then, if you have time left over and are curious abou Common Lisp's deep(er) internals, via the package system.
Riley S. Faelan
in reply to Tariq • • •This is a common Prolog problem because Prolog's way of pattern-matching can make the hard part implicit. Lisp doesn't do it on its own (although there's some tricks that could be pulled by CLOS, and, as always, one could start by implementing Prolog in Lisp, and then resort to the teapot principle).
What you're trying to do is searching for a pah through a (directed acyclic) graph, or depth-first search (aassuming you don't want o convert the input daaset into something different as a part of th procssing). Graph algorithms can be a useful searchword, or possibly ToCword. Most introductory programming (or Lisp programming) textbooks discuss at least the basic ideas of graph traversal, partly because, well, making graph problems relatively easy is kind of what Lisp is good at, and for a long while, didn't really have major competitors in.
Tariq
in reply to Riley S. Faelan • • •@riley
so if I try to think lisp rather than prolog by brain tells me I need to recursively follow all the paths from that starting point and use "nil" to fail the wrong ones.
that suggests some use of "OR path1 path2 path3 ... " where only the correct path with non-NIL is returned.
but I can't seem to get to the next step
Riley S. Faelan
in reply to Tariq • • •That's kind of the essence of depth-first search, yes.
I'm not quite sure if that's what you have in mind, but perhaps it helps: you won't be able to follow all the paths in a single
OR
. You'll have to follow them one by one (or via an abstract function that does that for you). You might want to use theLOOP
mechanism for this. (Common Lisp has a particularly fancy looping tool.)Tariq
in reply to Riley S. Faelan • • •@riley
Thanks I'll keep trying.
We haven't done loop yet so I'll think of other ways.
IPmonger
in reply to Tariq • • •Tariq
in reply to IPmonger • • •@IPmonger @riley
That's how I would do it by hand.. to follow paths to find the one that starts with x and leads to y, and fail the ones that ended not af y.
Perhaps that's why I'm struggling? My common sense approach is too complex?
IPmonger
in reply to Tariq • • •@riley Try to approach it more simply. Imagine each data entry is on a 3"x5" index card and they are collectively stored in a small box of an appropriate size.
Now, I ask you to personally use the cards to determine the lineage from linda to albert. What do you do specifically?
Tariq
in reply to IPmonger • • •@IPmonger @riley
In real life I would put start and end on the table and work in both directions forward from x and backwards from y.
By including the y I can reduce the search space
But that seems too complex for code.
Riley S. Faelan
in reply to Tariq • • •Computerised search on datasets like this is generally done in only direction, unless you'rea dealing with a large dataset and need heuristics, in which case there's some really interesting "like electricity" algorithms and heuristic pruning or search order techniques, generally falling under breadth-first search strategies, that may, indeed, search in both directions at once. These are probably out of the scope of this exercise, though. (The hint is, working on these would teach you graph algorithms, and you're supposed to work on learning how to think in Lisp.)
But sometimes, it can be useful for the one direction to go in the other way than what seems obvious.
The reasons for going only one way are numerous, some good, some so-so. For one, computers do not have human-like intuition, which factors into the optimal manual search patterns. For another, it's customary to aim for as simple algorithms as one can get away with. And historically, computer memory used to be very limited, so it paid to have both code and datasets to be tiny. Recall that Lisp is one of the two oldest programming languages still in actual use. Even COBOL is newer. When Lisp first came out, the concept of a computer being built of transistors, rather than thermionic valves, was the bleeding edge of tech, and the legendary PDP-1 got by with less than three thousand transistors, and only 4KiWords of memory in standard configuration. Modern computers are many orders of magnitude more capable, but some habits of these times are still culturally hard to break.
@IPmonger
Christine Lemmer-Webber
in reply to Tariq • • •sarabander.github.io/sicp/html…
minikanren.org/
miniKanren.org
minikanren.orgJonathan Lamothe
in reply to screwlisp • •@screwlisp Here's my naïve solution that I haven't bothered running through a compiler:
This assumes that all the
person
values are unique. It will potentially fail if not.Edit: renaming
Person
toPeople
and bugfixEdit 2: Actually, I don't think this will discard failed subtrees correctly.
Edit 3: Were I to try to fix this, I'd first change the type signature of
findTo
toEq a => a -> People a -> Maybe [a]
but I'm doing this all from a phone, not a real computer, so I'll leave that as an exercise to the reader.screwlisp likes this.
Jencel Panic
in reply to Jonathan Lamothe • • •Sensitive content
@me @screwtape Sorry, very sloppy of me, it is fixed now.
When I removed the accumulator I didn't realize that "ancessors father" and "ancessors mother" would never be null, simply because "ancessors" never returned null. The fix was to start returning null from 'ancessors' if 'extendedFamily' was null.
Jeremy List
in reply to screwlisp • • •Sensitive content
screwlisp reshared this.
screwlisp
in reply to Jeremy List • • •Sensitive content
```
flip lineage descendant) Nothing kids
```
Ah Haskell
@me @abuseofnotation @Regenaxer @rzeta0