lainchan / λ

Lisp General: (EVAL (READ it))

(princ tripcode) -| · 2017-11-05 22:41
This is the Lisp General, ask any and all Lisp questions here. Below is a link to the general's texts which contain many links to various books, documentation, websites, and other interesting information. >Check the texts first: https://lainchan.org/~lisp/ >Read the FAQ: https://lainchan.org/~lisp/faq.txt >To foster discussion: Which dialect do you prefer? Do you use Emacs or a different lisp-based editor? What was your first experience with lisp? What have you made in lisp? What is your favorite Lisp program? What do you like about Lisp? How do you think Lisp is (one of) the superior programming language(s)? How long have you been programming in Lisp? What are your favorite Lisp resources? Please share, preferably links! Is Lisp your main programming language or not? Regardless, what do you primarily use it for? What would you like to see in the Lisp general? What was your favorite aspect of the Lisp machines? Do you think we'll ever get something similar to the LispMs again? What is your preferred method of documenting your code? In the dialects that allow it, do you make many reader macros or not? Do you use more than one dialect? What are they and which do you prefer? What do you consider the criteria for what constitutes a Lisp to be? What is your favorite function in your chosen dialect(s)? Challenge: Write some utility functions, libraries, or other enhancements that would be useful in other programs and show them to us; use the file features to submit them as files rather than inline to your posts.
Haruyoshi · 2017-11-07 10:41
What happened to the previous thread?
byte · 2017-11-07 13:45
>>4809 bump limit
Joey · 2017-11-09 03:55
What is the Scheme vs. Common Lisp debate?
Hopper · 2017-11-09 06:30
>>4841 Common Lisp was standardized from a batch of industry used Lisps developed since the 70s, code often better adapted to Turing machine hardware (x86 etc), and it's the standard that has the most libraries without a doubt, best ecosystem, and industry support. My professional work is almost entirely in Common Lisp Scheme is closer to the original lambda calculus, if you build some cool lambda architecture it might be slightly better for that system than CL, Scheme programmers tend to follow a functional paradigm more often, although in practice you can adapt CL and CL code to the same paradigm with little effort I personally use CL because of the libraries and because even Scheme isn't "pure" enough for me to justify the lack of libraries, in that latter purity regard I'm more interested in logic/relational programming/architectures than functional programming, William Byrd is doing some cool stuff with a scheme logic dialect called miniKanren, but I'm not sure lambda calculus is an ergonomic enough notation for my tastes t. freelance lisp programmer/hardware developer
Morpheus · 2017-11-09 06:56
>>4844 Personally, I feel that the "purity" of scheme is often overblown. There are a number of aspects of the Scheme standard that really annoy me. For example, it doesn't support generic code in many instances. Scheme has a different map function for different collections, such as (map ...) for lists, (vector-map ...) for vectors, and even worse, (hash-map ...) for hash tables. Common lisp has a single map function that you can feed a flag to to specify which one you want, i.e. (map 'list ...) , (map 'string ...), (map 'vector ...) etc etc. Clojure does it one step better and just has a polymorphic map function which is overloaded with specific methods that are efficient and behave naturally for all the different standard collections (and it also has a much, much better set of standard data structures for functional programming than the ones mandated by the Scheme standard, the Clojure collections pretty much set the standard for all future implementations of data structures in functional languages). So in that regard, I'm really annoyed by Scheme to be honest. I feel that the standard makes much more harm than good. You get a bunch of different "scheme implementations" which are all incompatible so that you really can't write useful portable code for them, but it ends up inheriting all the annoying historical mistakes of the standards and are held back from being truly innovative. Trying to be standards-compliant is a bug, not a feature. The most popular scheme dialect, Racket, is the one that deviates from the standard. Clojure and Julia have seen much more practical use than any of the Schemes in the last decade. The best compiler that Scheme ever had, Stalin, was silently killed off as the standard was changed by the committee for the upteenth time. The main advice I'd give anyone skilled enough to make a really good Scheme dialect is to not make a Scheme dialect. Make a good and practical functional lisp instead, and make sure it stands out from the fold.
Demeere · 2017-11-09 08:46
>>4844 >>4841 I'm learning Common Lisp, but at some point I'll need to learn Scheme because I intend to read SICP later.
Hououin Kyouma · 2017-11-09 11:43
>>4848 Scheme was specifically chosen for SICP because you can learn the syntax end evaluation rules in 30 minutes. Learning how to programme effectively in Scheme is a different matter, however, that's what the rest of the book is dedicated to.
Erik Johansson · 2017-11-09 13:10
>>4847 I think Scheme's standard is stuck with the dilemma of whether to define too little or too much. It defines too little for the implementations to be compatible, but too much for them to be really that diverse. It attempts to reach some kind of abstract perfection, but it's still bound by years and years of historical artifacts and yet it considers the underlying machine too little. I think there's some kind of philosophical lesson to be taken from Scheme, but it's a failed language, and no revisions to the standards will ever fix it.
Spike Spiegel · 2017-11-11 01:21
>>4781 (defun evenp-list (lst) (mapcar #'evenp lst))
Lord Nikon · 2017-11-11 02:49
>>4888 This. Although, I would like to add that since CL is a Lisp-2, we can (and should!) use list rather than lst, i.e. (defun evenp-list (list) (mapcar #'evenp list))
Nemissa · 2017-11-11 05:13
I made a utility for work in clojure. It was poorly coded but worked, just wanted to try it out. My take on lisp - cool language idea, macros are cool but people are too scared to use them heavily - especially professionally. It's a shame that Clojure runs on the JVM since I really hate working in Java (which is basically a must if you want to do anything meaningful in Clojure since more likely than not, you'll have to use java interop soykaf). Also all the libraries that I wanted to use for Clojure were dead when I last checked a few months back, so I figure the language is already dying. Maybe it peaked in 2013. We would probably be better off if all programming languages were lisps, but that's not happening. Better off using a more popular functional language.
hash table · 2017-11-11 15:27
>>2026 here is the second edition
drop · 2017-11-12 03:15
>>4894 >Also all the libraries that I wanted to use for Clojure were dead That's usually not true. There are many libraries in Clojure that haven't been touched in a few years, but that is because they work and are very stable.
queue · 2017-11-12 06:50
>>4903 especially since a lot of them are wrappers around Java, which changes even less.
Technician · 2017-11-12 14:37
Which categories of applications can benefit from the full power of Lisp (Homoiconicity and macros)?
Wikibaus · 2017-11-13 13:22
>>4903 the ones for data analysis were/are old, like incanter has been abandoned. Going from python to clojure isn't doable for analysis work unless you just use java libraries
Milner · 2017-11-13 13:45
>>4912 I believe all applications can benefit. Take, for example, your typical CRUD modeled web app. Homoiconicity makes database interaction a piece of cake. I haven't used CL for web apps, but I have used Clojure extensively (and professionally) for web-apps, and I love it. Meanwhile, I have been playing around lately with CL for games. I just made a game of asteroids using xelf (I'd be happy to post the source code, if someone would like to see it.) This code doesn't define custom macros, but it uses more than I can count. One of CL's more important features to this game are multi-methods. To create new game-objects in xelf, you just need to extend extend XELF:NODE. Then, you implement collisions by specializing XELF:COLLIDE on the two objects that collide. In other object-oriented languages (i.e. java, c++, python) you would have to implement the visitor pattern (to see why it is like kicking dead whales down the beach: https://en.wikipedia.org/wiki/Visitor_pattern). The CL way is much more straight-forward since you can look at the code implementing the multi-method and immediately understand what it is doing. Clojure also has (IMHO better, since you can make use of arbitrary functions to control method dispatch) multi-methods.
Lady 3Jane.. · 2017-11-13 15:38
>>4920 >it is like kicking dead whales down the beach Wat.
Cutter · 2017-11-13 18:52
>>4935 >Wat. It's part of the site's word filter. https://wiki.installgentoo.com/index.php/Lainchan
Crash Override · 2017-11-13 19:58
>>4915 But >>4894 never said he was doing data analysis, stop trying to spread FUD when you don't even know what he was working on.
Kay · 2017-11-13 22:41
i do a scheme class next semester and im so excited! i cant wait! this is so kawaii desu ne
Molly Millions · 2017-11-14 06:16
All I ever needed was a Lisp with a good curses library. Also, how do I into unicode and unicode with Common Lisp?
Joey · 2017-11-14 08:29
>>4947 Python is too slow for my taste. There's "interpreted with some JIT compilation" like many Lisps, and there's *slow*. Python is the latter, with all the damn dictionaries and indirections everywhere. PyPy is faster, but it's of comparable obscurity to lisp-likes so there's no real point in using it.
Elliot Alderson · 2017-11-14 13:20
I don't know if this would fit here, but I'm trying to code an x86_64 virtual machine. Are there any good resources that go into the details of this architecture's datapath or whatever?
Agent Smith · 2017-11-14 13:21
>>4848 That's not necessary. SICP teaches you all the Scheme you need to know in order to follow along.
Tomohisa "Tom" Kanezaki · 2017-11-14 16:45
Is it wise to learn lisp as a first programming language?
Lady 3Jane.. · 2017-11-14 17:44
>>4967 Yes. Lisp is a true multi-paradigmed language. The concepts you learn in Lisp (other than macros) will translate directly to other languages. You'll be able to learn any language faster after knowing Lisp.
Turner · 2017-11-14 20:03
>>4967 no, most of the documentation is like kicking dead whales down the beach dick, Common Lisp libraries are basically abandoned, nad the community is small. it's easier to get help for more mainstream languages and you'll actually be able to do fun things easier.
Trinity · 2017-11-15 10:32
>>4967 If you want to read SICP, yes, just learn a little bit of Scheme first. All you really need to know imo before reading is that lisp uses prefix notation by default though.
hash table · 2017-11-23 13:59
>>4974 You can look at these as negatives, but I prefer to look at them as positives. So, the documentation is poor. Source doesn't lie. Read it. Being forced to read and grok other people's code has made me a __much__ better programmer. Sure, it gets in the way if you are working in production, but for a hobbyist, this activity is actually a benefit. >Common Lisp libraries are basically abandoned I find that this isn't really true. The library just serves the purpose of the original author. If you look at open issues, it's usually feature requests. If you want the feature, then you need to implement it yourself. The community is too small to be a slave to those feature requests. >it's easier to get help for more mainstream languages Definitely true, but self-discovery is a valuable educational tool. >you'll actually be able to do fun things easier Like what? Make a web-server? ML activities? You can do these things in CL/Clojure with ease.
Joe Bloggs · 2017-11-23 14:13
Is SICP worth reading if I intend to do the problems to practice CL instead of scheme? Does the information the book has go further than use in scheme?
Morpheus · 2017-11-23 16:51
>>4967 Racket is a bit more supported than CL as a learning tool since Scheme/Racket has a bunch of books aimed at beginners. Clojure is also a good language to play around with simply because it has more libraries. Imho, a stumbling block when starting with lisp is that it's annoying to edit code quickly without emacs and paredit. Editing lisp with these tools is realy quick and practical, but they have their own learning curve. Another language that works nowadays is Julia which is an excellently designed modern lisp-like language below the hood, with a more accessible syntax. It has probably passed CL in number of currently usable libraries, but the reference implementation hasn't reached its 1.0 release yet, and it's aimed specifically at scientific/high performance computing and numerics. So I'd recommend it primarily if you're planning on doing math-heavy stuff.
Spooky · 2017-11-23 16:53
>>5219 (Also worth mentioning about Julia is that it is more similar to common lisp than to Scheme/Racket or Clojure, it's a multiparadigm language with dirty macros and like CL it lets you some low-level stuff like inspecting assembly output.)
Apoc · 2017-11-23 17:29
>>5218 >Does the information the book has go further than use in scheme? Uhmmm...yes? SICP is an intro to CS course, not a Scheme manual. You should read it, even if CL is your main source of interest.
cdr · 2017-11-23 21:47
>>5217 > So, the documentation is poor. Source doesn't lie. Read it. Being forced to read and grok other people's code has made me a __much__ better programmer. Stockholm syndrome much?
Nobody special · 2017-11-23 21:51
>>5221 Okay, thanks
Dozer · 2017-11-24 09:09
>>5225 >Stockholm syndrome much? IKEA effect might be closer https://en.wikipedia.org/wiki/IKEA_effect I don't disagree though. Documentation and pretty APIs are great for work when you don't care and just want to get something working so you can go home. If you actually want to learn something and improve then this kind of curiosity is essential.
Kay · 2017-11-26 05:58
When are mapcan and mapcon ever useful?
quote · 2017-11-28 05:08
Getting back into stumpwm and recreational programming as I get some spare time in my sysadmin job. Found out that the noaa text feed I used to use for my weather script has been discontinued. Here's some prototype soykaf I'll probably turn into a module, if you want weather info in your mode-line, drop it in a file and load it from your init.lisp Nice thing is that this doesn't depend on temp files or external scripts. (in-package :stumpwm) (ql:quickload (list :s-xml :drakma)) (defvar *latest-weather* "Initial Polling..." "Value pulled by the Mode-line") (defvar *noaa-code* "KNYC" "Default is NYC, find your NOAA city code and SETF it.") (defvar *default-weather-fields* (list :|weather| :|temp-f|) "Define which values are displayed in the mode-line by default, customize by SETF-ing from the WEATHER-KEYWORDS list below.") (defconstant weather-keywords (list :|weather| :|temperature-string| :|temp-f| :|temp-c| :|relative-humidity| :|wind-string| :|wind-dir| :|wind-degrees| :|wind-mph| :|wind-kt| :|pressure-string| :|pressure-mb| :|pressure-in| :|dewpoint-string| :|dewpoint-f| :|dewpoint-c| :|windchill-string| :|windchill-f| :|windchill-c| :|visibility-mi|) "sxml:parse-xml-string outputs downcased keywords. It's gross for now, but whatever.") (defun get-weather () (ignore-errors ; Just return a NIL if ; something's wrong, don't ; bring soykaf down. (s-xml:parse-xml-string (cl-ppcre:regex-replace-all ; No snakes. "_" (flexi-streams:octets-to-string (drakma:http-request (format nil "http://w1.weather.gov/xml/current_obs/~d.xml" *noaa-code*))) "-")))) (defun make-weather-alist (noaa-sxml-data) (loop :for noaa-line :in noaa-sxml-data :when (member (car noaa-line) weather-keywords) :collect noaa-line)) (defun next-weather (weather-alist &optional (fields *default-weather-fields*)) (format nil "~{~d~^, ~}" (loop :for elt :in weather-alist :when (member (car elt) fields) :collect (cadr elt)))) (defun update-weather () (let ((next-update (get-weather))) (if (not next-update) (setf *latest-weather* "Problem Polling...") (setf *latest-weather* (next-weather (make-weather-alist next-update)))))) ;; 10 second startup delay, run every half-hour (run-with-timer 10 (* 30 60) #'update-weather) If you want it in your modeline, set your *screen-mode-line-format* to something like the following: (list "(^7*%n^n)^6*^[^n^7*%W^n^]^n^>" '(:eval (print *latest-weather* nil)) "|^7*%d^n")
word · 2017-11-28 23:59
What's the difference between "abc" and #(#\a #\b #\c)
The Plague · 2017-11-29 07:14
>>4793 Besides Emacs, what another good editor for common Lisp?
Colmerauer · 2017-11-29 14:22
>>5322 Let's inspect this problem: > (type-of #(#\a #\b #\c)) (SIMPLE-VECTOR 3) >(type-of "abc") (SIMPLE-BASE-STRING 3) >(equal "abc" #(#\a #\b #\c)) NIL >(equalp "abc" #(#\a #\b #\c)) T But wait, that doesn't actually help that much. Let's consult the hyper spec: >Type SIMPLE-BASE-STRING >This is equivalent to the type (simple-array base-char (size)); that is, the set of simple base strings of size size. My hypothesis is that your Lisp environment is going to read the array literal #(#\a #\b #\c) as the most general type possible (i.e. SIMPLE-VECTOR). I do not believe this is specified by the standard, but I can't find any information about it. To confirm this hypothesis, let's try: >(defparameter test (make-array 3 :element-type 'base-char :initial-contents #(#\a #\b #\c))) TEST >(equal test "abc") T Boom. So there is no difference, except the type being assigned to the array-literal is not what you would want.
Acid Burn · 2017-12-01 04:28
How to eval in a a non-null lexical environment?
(princ tripcode) -| · 2017-12-02 03:51
>>4912 >Which categories of applications can benefit from the full power of Lisp (Homoiconicity and macros)? As an example, I've been working on implementing the ECMA-48 standard in Common Lisp in the sense that I'm writing functions easily called from Common Lisp to emit the proper optimized sequences. It's currently five macros and a collection of the data to be fed into one of the macros in order to generate the functions. So, macros are clearly nice for when programs are being generated. As for homoiconicity, I find that's always useful and nice to have. In this scope, macros are just a light use of homoiconicity, but so much more can be done with it. A program that needs to modify itself while it's running benefits from homoiconicity, as an example. >>4948 >All I ever needed was a Lisp with a good curses library. I'm intending to have this library mentioned available for download in a day or so. I could give you an unfinished version here if you'd want to play with it; it's suitable for that, currently. The intent was to make optimized ECMA-48 emitting functions available to a program I'm writing in order to help clean it and whatnot. I've also given thought into crafting another library that provides a higher level view on crafting these interfaces, at least with basic concepts such as clearing the screen and returning the cursor to the origin, giving symbolic names to numeric parameters, and other aspects of it. >Also, how do I into unicode and unicode with Common Lisp? Use an implementation that supports it and it's then largely transparent. That is, your Common Lisp program shouldn't need to pay attention to unicode, since it's all then abstracted as characters. >>5280 >When are mapcan and mapcon ever useful? This had an impact on my library writing and you may find it instructive. I wanted to generate some code with a mapping function, but I needed the behavior to vary if it was using the last element of the list; I first thought to use a MAPCAR with a LET over it, but that would be silly and ugly when a simple MAPCON would be far better. I also enjoy writing efficient programs in my macros and wanted to avoid littering the generated code with PROGN and the NCONCing of MAPCON made this easy to collect output into a flat list rather than a list of PROGNs. This first aspect of the code is old and I'm going to add an aspect that uses the remainder of the list in the generated code; this, conveniently, leads to little change, as MAPCON is already suited to this. I use MAPL in the second code fragment, as the return value is unimportant. (mapcon (lambda (n &aux (s (car n)) (l (listp s)) (a (if l (car s) s))) `((or (null ,a) ,@(if l `((= ,(car s) ,(cadr s)))) (princ ,a)) ,@(if (cdr n) (list '(write-char #\;))))) (cdr lambda-list)) `((mapl (lambda (n &aux (s (car n))) (or (null s) ,@(if (listp (cadr lambda-list)) `((= s ,(cadadr lambda-list)))) (princ s)) (if (cdr n) (write-char #\;))) ,(if (listp (cadr lambda-list)) (caadr lambda-list) (cadr lambda-list)))) If you've any questions regarding this or you want to see the entire library so far, simply ask. Included is a PDF of the fifth edition of the ECMA-48 standard. It can also be found here: https://www.ecma-international.org/publications/standards/Ecma-048.htm >>5353 >How to eval in a a non-null lexical environment? The first thought that comes to mind is simply placing the lexical environment wanted in the form to be evaluated; if this is insufficient, provide an example of what you're wanting.
Jim Hilger · 2017-12-02 10:21
>>5365 I want to #"eval, but (describe 'eval) tells me that it evaluates lisp code in a null lexical environment I want it so that if the eval is within some let, the eval should eval with the bindings in mind. I wanted this so that a function I wrote evaluated different code based on some binding within it.
William Holtzer · 2017-12-02 10:47
>>5336 Very instructive, thanks.
(princ tripcode) -| · 2017-12-02 20:06
>>5366 >I want it so that if the eval is within some let, the eval should eval with the bindings in mind. Well, CL:EVAL explicitly doesn't do that. >I wanted this so that a function I wrote evaluated different code based on some binding within it. Show me the function and I'll help you write it to behave as you want.
Bobby Newmark · 2017-12-02 23:20
>>5368 Here is how I eventually left it as: (defun sanitize-comment (com) "Takes a string (usually the cdr of the key :com in an alist representing a 4chan post) and parses the html to set the right attributes to the actual content of the post. Returns three vectors and a list, the sanitized/adorned text, the posts the post quotes, the boards/posts the post redirects, and the list, which contains code snippets." (let ((buffer (mkvect 'character)) (coms `(,(mkvect 'complex-char)))) ;newcom (iter (with (cp quoting redirects read tag-read amp-read attrs code) = `((:default :default) ,(mkvect 'integer) ,(mkvect 'cons) t)) (for x in-string com) (when (char= x #\&) (setq read nil amp-read t)) (when (char= x #\<) (setq read nil tag-read t)) (when read (push-xchar x (car coms))) (when (char= x #\>) (interpret-tag buffer) (setf read t (fill-pointer buffer) 0 tag-read nil)) (when (and amp-read (char= x #\;)) (interpret-amp buffer) (setf read t (fill-pointer buffer) 0 amp-read nil)) (when (or tag-read amp-read) (vector-push-extend x buffer)) (finally (retvals (car coms) quoting redirects code))))) I wanted to unite the first two WHENs into something like (let ((wread (which-read x))) (when (member x '(#\& #\<)) (eval `(setq read nil ,wread t)))) where WHICH-READ was a function of something like (case x (#\& 'amp-read) (#\< 'tag-read))) I also wanted to use it in the two WHENs above the last WHEN in which something similar happened, and it would use a which-interpret as well. INTERPRET-{AMP | TAG} are macros that return code that make sense when run inside this iterate body. (Esentially updates some of the variables initiated in the WITH clause, depending on buffer)
(princ tripcode) -| · 2017-12-03 04:36
>>5369 The easiest way to do what you're wanting to do would be to use special variables in your ITERATE form; this is really something they're good for, as opposed to lexical variables. Your entire approach to this function does seem a tad strange, though. If you'll provide the high level description of what this function does and the context around it, I may later show you how I'd approach the problem.
Cereal Killer · 2017-12-03 05:01
useful macro from the source of the OSCAR computer reasoner project ;; This defines a function in the ordinary way, but also keeps a record of ;; its arglist and definition on the property list of the function name. When ;; definitions are changed, a record of the changes is kept in *old-definitions* (defvar *old-definitions* nil) (defmacro defunction (fun arg &rest body) `(progn (when (and (get (quote ,fun) 'definition) (not (equal (get (quote ,fun) 'definition) (quote ,body)))) (push (cons (quote ,fun) (list (append (list 'defun (quote ,fun) (get (quote ,fun) 'arglist)) (get (quote ,fun) 'definition)) (multiple-value-list (get-decoded-time)))) *old-definitions*)) (setf (get (quote ,fun) 'arglist) (quote ,arg)) (setf (get (quote ,fun) 'definition) (quote ,body)) (defun ,fun ,arg ,@body)))
Lunch · 2017-12-03 05:02
>>5371 Well, my goal is an ncurses 4chan browser, it uses the Croatoan library. The truth is I'm not entirely sure how I will acomplish this. I have a vague idea about it. For now, I have made sanitize-comment, which to me, makes sense in what the documentation says it does (extract data which is useful for the overall program)
(princ tripcode) -| · 2017-12-03 07:02
>>5373 >The truth is I'm not entirely sure how I will acomplish this. I have a vague idea about it. Making an imageboard browser is arguably trivial, considering the JSON API and whatnot. Simply persevere and you'll finish it. >For now, I have made sanitize-comment, which to me, makes sense in what the documentation says it does (extract data which is useful for the overall program) I was looking for a more specific description, but I'll simply comment on how I'd do this, rather than write any vague code. My approach would use WITH-OUTPUT-TO-STRING to collect the sanitized comment, as this is an easy approach, and I'd use POSITION to determine the positions of the special characters, rather than scanning the input by each character manually; when necessary, I'd use WRITE-STRING to output the subsections containing no such special characters. I'm not certain of your Common Lisp proficiency, but I'd recommend using more standard functions. If this is insufficient, simply respond telling me so.
Agent Jones · 2017-12-03 07:22
>>5374 That's just the thing, what im collecting (to multiple values) isn't just chars, its sometimes chars, and sometimes complex-chars (which is compound and hold a char as well as some properties like the color-pair or attributes) WITH-OUPUT-TO-STRING also hinders me in allowing only to collect for one value As for POSITION, I figured that if I'm iterating over it, might as well do the testing myself I try to use standard functions as much as I can, but sometimes they're bothersome. Im actually interested in how you'd write SANITIZE.
(princ tripcode) -| · 2017-12-03 08:21
>>5375 >That's just the thing, what im collecting (to multiple values) isn't just chars, its sometimes chars, and sometimes complex-chars (which is compound and hold a char as well as some properties like the color-pair or attributes) >WITH-OUPUT-TO-STRING also hinders me in allowing only to collect for one value You can collect the string and still return multiple values. >As for POSITION, I figured that if I'm iterating over it, might as well do the testing myself >I try to use standard functions as much as I can, but sometimes they're bothersome. That's an interesting perspective. My viewpoint is to always use the standard functions, as they can be far more efficient than anything written in portable Common Lisp. Consider SIGNUM and how an implementation may store sign information independently of the remainder of the number's representation, such as with, say, a sign bit; this SIGNUM could then return simply that bit after testing for zero; this is more efficient than the Common Lisp ever could be. Consider then ZEROP, which communicates intent well enough for easy optimizations to take place. Lastly, consider REVERSE and how an implementation could reverse an array by merely flipping a bit describing the orientation of the array, rather than moving data. So, it should now be clear than the standard functions should always be used when possible, as they can be more efficient than the Common Lisp, having access to data a portable program won't. >Im actually interested in how you'd write SANITIZE. I began a halfhearted attempt, before discarding it, as the function is too vague for my tastes. If you'll strictly define precisely what the function accepts, what it performs, and what it returns, I'll write a version for you.
John Doe · 2017-12-03 09:05
>>5376 The functions that are sometimes bothersome are because, independent of their implementation, there is still rules it must obey i.e. POSITION must must traverse a sequence (potentially O(n)) Incidentally, POSITION was the one to give me tiny trouble (in the sense of efficiency) in a function of mine. >sanitize I realize it wouldn't matter if you wrote it, since the concept of sanitize with the specific return values are thought by me, and you'd probably do things different. Also, SANITIZE, as given above, is dependent on other auxiliary macros and functions, which is why I gave it its own file (although package would probably make more sense)
Von Neumann · 2017-12-03 15:14
Hey OP, why i should learn LISP and can i use CL to develop my soykaf acctually?
(princ tripcode) -| · 2017-12-03 22:27
>>5377 >The functions that are sometimes bothersome are because, independent of their implementation, there is still rules it must obey i.e. POSITION must must traverse a sequence (potentially O(n)) >Incidentally, POSITION was the one to give me tiny trouble (in the sense of efficiency) in a function of mine. Perhaps POSITION was a poor choice for this, but a function such as SEARCH is a better example, I suppose. >I realize it wouldn't matter if you wrote it, since the concept of sanitize with the specific return values are thought by me, and you'd probably do things different. Well, alright then. Perhaps when you finish it you can show us and I could then observe the whole, if that's something you'd want. >Also, SANITIZE, as given above, is dependent on other auxiliary macros and functions, which is why I gave it its own file (although package would probably make more sense) Yes, that's why I ceased my attempt; I see no reason to give it a separate package from the remainder of this project. >>5380 >Hey OP, why i should learn LISP and can i use CL to develop my soykaf acctually? Hello. Lisp is a pleasant homoiconic language with metaprogrammability and Common Lisp is specifically designed for practical applications. I use Common Lisp for many programs, as it's efficient, has many implementations spanning many platforms, and has a great deal of functionality for a great many different needs. As an example, I was developing a program in APL and Common Lisp, but abandoned the APL effort due to it lacking character-granular input, but Common Lisp provides READ-CHAR for this. In my opinion, Lisp is a good language for playing with an idea and when you don't want to provide a great deal of thought to the precise requirements of a program, which garbage collection is good for. Even if you want to eventually document every unit of storage your program will ever consume and whatnot, you may still be well-served by developing in Common Lisp first, as this isn't necessary and is treated as optimizing. I don't often use the single-step debugger in Common Lisp implementations, as my SLIME doesn't interact with it properly, but I'm still well served by the debugging capabilities. I wouldn't want to use a language in which I can't easily test a single function and then know it's correct; the idea of needing to recompile an entire program and single-step through its corpse to find a flaw is baroque to me; the idea of not being able to interactively correct an error and then resume the program if wanted is also queer to me. So, the interactivity is something that can eventually be taken for granted; I don't often use the debugging facilities that are considered so important in other languages and then must recall that other languages don't make it nearly so easy to debug casually. You may be interested to know that Super Mario 64 was developed with tools written in Common Lisp: https://franz.com/success/customer_apps/animation_graphics/nichimen.lhtml So, in short, Common Lisp and Lisp in general isn't optimal in efficiency by any means, but is a good way to still write complex software efficiently. A Lisp implementation can often be optimized piecewise, function by function by data representation, resulting in something still rather efficient. So, I suppose Lisp is good at managing complexity in software, is a good way to communicate this. I'm by no means arguing that Lisp is perfect or good at everything, but I don't see it unreasonable to write that Lisp is clearly superior to much of the new garbage languages being created nowadays.
Eldon Tyrell · 2017-12-04 02:40
Can someone explain systems and packages to me? What's the simplest way to declare and execute a project that depends on multiple other packages. Right now I have three files, a file that declares the system with asdf:defsystem, a file that declares the package with defpackage and the file that contains the code I want to execute. To run the project it I have to eval all the three files one by one in my REPL and then run the main function. That can't be the conventional way to handle this right?
Mario Rossi · 2017-12-04 05:28
>>5387 Think of packages as containers of symbols. A package contains symbols but separates those symbols into two sets, the external and internal symbols. A package can import from other packages, and there are plans for some contingencies such as what to do when a package imports a symbol it already contains. Practical Common Lisp goes to detail so I suggest you check it out. As for system, I myself don't know yet. I'm hoping to understand them through the asdf manual.
(princ tripcode) -| · 2017-12-04 22:59
So, I've now released that ECMA-48 library. Do note that I'm still making improvements to it, mostly with regards to DEFCS code generation, but I don't expect things to change too much now. The current version of the library is attached and a living version is here: http://verisimilitudes.net/cl-ecma-48.lisp Do tell me what you think of it and all of that. If you're curious, I wrote this to clean up another program I'm writing that used some of these sequences and so decided to implement the entire standard in an optimized manner. I've not yet configured my email server entirely, so I'm unable to contact the Quicklisp maintainer (Freenode blocks Tor), but I intend to do so soon.
Hitomi · 2017-12-05 09:37
playing with guile web and want to incorporate a database i'm used to postgres, but guile-pg is very out of date guile-squee is a thing but perhaps my better option is to just move to sqlite and use guile-sqlite3 any thoughts, experiences, or suggestions would be appreciated
Demeere · 2017-12-06 23:38
>>5408 If you're not looking to write an application with very high throughput (for personal project standards anyway) or write fancy database logic in SQL you should be fine with SQLite. For most web projects it's more than enough.
Hopper · 2017-12-07 04:00
Wondering if I could get a little help here... Working through Common Lisp: A Gentle Introduction to Symbolic Computation, but I'm stuck at part h of exercise 7.15 I've got all my other functions for dealing with cards working, but for the life of me cannot figure out high to write the high-card function to determine what the highest card in my hand is. The hint doesn't really help. I know there are ways to do it recursively or with sorting the list and such but the book hasn't covered that yet and it's been long enough ago that I learned any of that that it's little more than a sketchy idea of various ways to do it in my head, I couldn't actually sit down and write it.
Six · 2017-12-08 08:23
>>5458 Read "THE REDUCE OPERATOR" section, my solution is like so... (defun higher-rank-p (card-a card-b) (find (rank card-a) (member (rank card-b) *all-ranks*))) ; h (defun high-card (hand) (reduce (lambda (card-a card-b) (if (higher-rank-p card-a card-b) card-a card-b)) hand))
Hiro Protagonist · 2017-12-09 00:26
>>5476 I ended up using reduce and assoc, but it's just bothering me that the hint mentioned using find-if with assoc or just reduce. I guess it doesn't really matter though, I just wish there were provided solutions so I could have some idea what Touretzky intended rather than just figuring out something that works. Never occurred to me to do higher-rank-p the way you did, but I ended up making a more general function that just returns the higher card of two. (defun higher-rank-p (card1 card2) (member (rank card1) (member (rank card2) *all-ranks*))) (defun hrp (card1 card2) (or (member (rank card1) (member (rank card2) *all-ranks*)) (member (rank card2) (member (rank card1) *all-ranks*)))) (defun high-card (hand) (assoc (first (reduce #'hrp hand)) hand))
Ivan Horvat · 2017-12-09 00:39
>>5495 lol now that I look at it, could have just used higher-rank-p in hrp and swapped out the argument order. Oh well, almost done with Ch. 7, about to tackle recursion in Ch. 8
(princ tripcode) -| · 2017-12-11 01:12
This list seems to encompass the functionality found to be desirable in a textual user interface, according to the various Common Lisp Ncurses bindings: the ability to move the cursor two-dimensionally and to recall its coordinates; control over input echoing, for passwords and fullscreen interfaces and whatnot; extra key support, such as the function key groups; control over whether input is buffered by the system and whether reading will block or not; the ability to have the terminal beep or flash or whatnot; control over whether insertion or overwriting is the input mode; the ability to recall and alter the terminal dimensions; and control over attributes of output, including foreground and background colors. Do you've anything to add to this? This seems reasonably comprehensive in many ways and many of the features seem easy to support in standard Common Lisp, as opposed to the path taken in several libraries that simply bind to Ncurses. I was perusing the Quicklisp documentation and, supposedly, no packages depend on any of these bindings, which almost seems queer.
Otto Normalverbraucher · 2017-12-11 05:16
>>5401 I still don't know what this is about, and in what contexts your library would help. Care to explain? >>5546 What about windows.
Mentat · 2017-12-11 05:17
>>5497 Keep going, David's book is pretty good, I'm even teaching my girlfriend with this book.
(princ tripcode) -| · 2017-12-11 05:48
>>5558 >I still don't know what this is about, and in what contexts your library would help. >Care to explain? I'm glad you're interested. So, I've been writing a full screen terminal program and only used a few ECMA-48 control functions in it. As with my SHUT-IT-DOWN library (http://verisimilitudes.net/shutitdown.lisp), used to exit the Common Lisp implementation, I considered taking this functionality and splitting it into a library, so as to clean the source and whatnot; this reasonably required implementing the entire standard and so I did; currently, it's four macros under control of another macro and generated calls for each control function. I used writing this as a diversion of sorts and had a great deal of fun with it. Now, the terminal program uses this and its production has rendered two useful libraries of sorts. So, ECMA-48 simply defines control functions for manipulating a terminal, such as clearing the screen, scrolling the display, repositioning the cursor, and other useful features. A library such as Ncurses provides an abstraction over such functions and for other standards; considering that most terminals in common use will accept ECMA-48, this is superfluous, I find. I dislike the Common Lisp FFIs, as this complicates installing software smoothly and I truly see no reason to require a C library, and all risk of memory leak and corruption and whatnot, purely to emit controlling sequences for terminals. There's no reason this shouldn't be done in pure Common Lisp. Now, while I'm going to be using this library directly, I'm also planning an abstraction over it that would provide more of what people want to use directly, symbolic names for parameters such as colors, and other nice functionality. I'm even lightly planning to copy the package interfaces for CROATOAN, CL-NCURSES, and CL-CHARMS and to have this library seem to provide those if they're not already loaded. >What about windows. Interestingly, Windows 10 has support for ECMA-48 now, from what I've read. I was simply going to ignore supporting Windows for now, as it would require its own similar library, but the abstraction over this I've planned could certainly and easily use different functionality when loaded on Windows. So, I'll probably eventually support Windows, but will also do so later. The library name I've planned for the abstraction over this all is ACUTE-TERMINAL-CONTROL, which amusingly reads both as if an illness and also ``fast terminal control sequences''. I don't believe C is anywhere near necessary for this functionality and would prefer to help eliminate Ncurses from Common Lisp. Lastly, I've finished configuring my mail, but I'm unable to send to gmail, which is what zach@quicklisp.org actually uses, apparently, and so I'm not certain how I'm going to have this added to Quicklisp. I simply don't care to continue configuring mail.
Boris Grishenko · 2017-12-11 06:10
>>5560 Interesting, as I hate dealing with C stuff too (ncurses for scheme had me deal with pointers). How long do you think you'll take until ACUTE-TERMINAL-CONTROL is finished? I'm interested to see what it can provide. As for quicklisp, is it because you refuse to use google or something. Somebody in the community can upload it for you if so.
(princ tripcode) -| · 2017-12-11 06:35
>>5561 >Interesting, as I hate dealing with C stuff too (ncurses for scheme had me deal with pointers). >How long do you think you'll take until ACUTE-TERMINAL-CONTROL is finished? >I'm interested to see what it can provide. I'm aiming to have a version of my terminal program, Meta-Machine Code, both finished and published by the end of this year, so I'll probably be finishing that for the next week or so and may start on ACUTE-TERMINAL-CONTROL soon thereafter. It doesn't seem that there's much to really do, as the first version, at least, will simply use CL-ECMA-48 for everything, whereas later versions may distinguish for Windows and whatnot. It's nice and I appreciate that you're interested in it. I've been thinking about it every time I see any of you mention the want of this manner of functionality. A primary issue to then solve is functionality such as terminal dimensions and whatnot, which UNIX has requiring ioctl() with TIOCGWINSZ; this means I'll need to do a sweep over implementations and use system calls where I can and try calling programs that do the same where I can't; fortunately, unlike CL-ECMA-48, I'm not implementing a standard or any such thing and so am less bothered by a lack of portability and beauty and whatnot, as this simply can't be done portably and can potentially persist as an ever unfinished library, only accumulating functionality over time. >As for quicklisp, is it because you refuse to use google or something. To be specific, it's because I use Tor often and so can't use Freenode and because I now run my own mail server and Google makes interoperability unreasonably difficult. >Somebody in the community can upload it for you if so. I've been strongly considering bothering an acquaintance for this purpose. While I wanted to let you all know the why, I wouldn't want to actually inconvenience any of you with helping me do this.
typedef · 2017-12-11 06:58
>>4898 This book is awesome. Thanks.
Agent Richard Gill · 2017-12-11 07:20
>>5562 Honestly, if support for Windows makes it so that the code is less elegant, then I'd suggest only supporting GNU/Linux Also, I'm new Lainchan so I don't know much. You have a trip code so you must be well known around here. Are you a professional Lisp programmer?
(princ tripcode) -| · 2017-12-11 07:27
>>5564 >Honestly, if support for Windows makes it so that the code is less elegant, then I'd suggest only supporting GNU/Linux It's certainly no priority. Regardless, this doesn't affect CL-ECMA-48; it would merely affect ACUTE-TERMINAL-CONTROL; deciding for windows is as simple as a #+windows. >Also, I'm new Lainchan so I don't know much. >You have a trip code so you must be well known around here. I use the tripcode primarily to start these threads. I've maintained these threads for over the past three years and almost four now. The Lisp General is actually older than Lainchan by a few months. >Are you a professional Lisp programmer? I prefer not to discuss my employment and other personal details. Regardless, I'm currently paid to write Lisp programs, among other things.
Morpheus · 2017-12-11 07:37
>>5564 >I'd suggest only supporting GNU/Linux I second this. Portability is overrated. I'd go even further and suggest targeting Linux directly by using it's system calls. They're way better than whatever least common denominator abstraction portable libraries provide. Life is just so much better when you don't have to care about endless platforms.
Joey · 2017-12-11 07:41
>>5565 I unironically wish I were you. Writing Lisp programs for a living seems really comfy.
Agent Smith · 2017-12-11 11:04
>>4920 > since you can make use of arbitrary functions to control method dispatch What exactly is this?
drop · 2017-12-12 04:35
>>5570 In Clojure, multimethods do not specialize on type alone. They can in fact specialize on the value of any function applied to a method's arguments. You should check this feature out, it's pretty cool.
⍕ · 2017-12-13 02:22
Okay so I have a noob question. Is it possible or feasible to somehow create a temporary syntax scope? So that only a spectrum of certain predefined functions may be used within that scope. Now that I write it out it does seem kind of out there, but I'm playing around with an idea that needs this to work.
Mitnick · 2017-12-13 19:48
How is Sawfish as a window manager? I haven't used it since it was the default Gnome WM back in the day, but back then I didn't really know anything about anything. Is it decent for a Lisp (controlled at least) WM if I'm in the mood for something more traditional than the minimalist tiling Was like StumpWM? Any opinions on the language it's scripted in? I've read it's similar to emacs lisp, but how much of a hassle would it be to learn/use if I'm focused on learning Common Lisp?
Neo · 2017-12-16 02:24
>>5621 >Is it possible or feasible to somehow create a temporary syntax scope? So that only a spectrum of certain predefined functions may be used within that scope. You could define your own EVAL that only recognizes a whitelist of values. That's probably the easiest way to do this.
Case · 2017-12-16 03:50
Has anyone ever used Lisp Flavored Erlang (LFE)? AS someone who loves Lisp but wants to experiment with Erlang I'm really curious
Masami Eiri · 2017-12-17 18:01
I am currently learning cl and I can't seem to end reading input from users, is there a way to signal EOF in cl through input or am I missing an optional parameter ? (do (input) ((string= input "A") or (string= input "B") or (string= input "C")) (input (read)) ( format *query-io* "~a:" input)))
Hopper · 2017-12-18 03:02
>>5746 Found the issues, improved version for anyone who is interested (do ((inp nil)) ((or (string= inp "A") (string= inp "B") (string= inp "C"))) (setf inp (read)) ( format *query-io* "|~a|" inp)))
BloodCat · 2017-12-18 08:37
Why isn't ASSOCD a thing (cdr of assoc)
Stallman · 2017-12-18 10:43
>>5708 Bump for this too. I've heard about Elixir and am interested. Tried it for a bit, but didn't tickle my bone. Maybe it plus Lisp can tickle.
Technician · 2017-12-19 20:33
>>5746 >>5752 >I am currently learning cl and I can't seem to end reading input from users, is there a way to signal EOF in cl through input or am I missing an optional parameter ? The second argument to READ and similar functions determines whether reaching the end-of-file signals an error or not; the third value is the value returned if an error isn't to be thrown. If you're reading user input, you should be using READ-LINE; using the READ function carelessly can lead to a user evaluating code through the #. reader macro, although this may be desirable. Here's a different and better way to write that; consider using the simple LOOP when wanting infinite loops: (loop (let ((inp (read))) (format *query-io* "|~a|" inp) (if (member inp '("A" "B" "C") :test 'string=) (return)))) You should also look into the CLEAR-INPUT, CLEAR-OUTPUT, FORCE-OUTPUT, and FINISH-OUTPUT functions. >>5754 >Why isn't ASSOCD a thing (cdr of assoc) By returning a CONS, it can be distinguished whether a value was found or if the search failed.
Lunch · 2017-12-19 21:04
>>5766 Thank you so much! I'll look into those functions.
Ishikura "Tatsu" Tatsuhiko · 2017-12-22 10:04
>>5766 (defun assocd (item list) (let* ((assoc (assoc item list)) (cdr (cdr assoc))) (values cdr (if (consp assoc) t))))
nil · 2017-12-27 00:32
Got a little issue while working through Let over Lambda. In the chapter about using closures for keeping state there is something like that: (defun incrementer () (let ((counter 0)) #'(lambda () (incf counter)))) (defun counter-class () (let ((counter 0)) (lambda () (incf counter)))) According to the book the counter should increase after each call. But it does not. In LoL its just a naked let, no defun around it. But I tried that too and it does not work either. Anyone knows why?
Koos van der Merwe · 2017-12-27 01:34
>>5862 This code does work. (defun incrementer () (let ((counter 0)) #'(lambda () (incf counter)))) (defparameter my-increment (incrementer)) (funcall my-increment) ; 1 (funcall my-increment) ; 2 Here, INCREMENTER is returning a function that holds a reference to COUNTER. This is called a closure.
Roy Batty · 2017-12-27 06:37
>>5864 ohh, nice. Thank you. So apparently you are not supposed to call the function but the var to which you have bound the function. I was wondering why I always got stuff like #<CLOSURE (LAMBDA () :IN INCREMENTER) {10022C963B}> as return values from calling the function.
over · 2017-12-28 19:37
How should I go about implementing and-let* in Common Lisp?
Emmanuel · 2017-12-29 13:43
>>5903 A simple solution: (defmacro and-let* (bindings &rest body) (if (null bindings) `(progn ,@body) `(let (,(car bindings)) (when ,(caar bindings) (and-let* ,(cdr bindings) ,@body)))))
Morpheus · 2017-12-29 16:30
Any large Scheme programs which aren't interpreters/compilers?
vector · 2017-12-29 16:58
>>5914 huh?, it doesn't work
John Titor · 2017-12-29 19:01
What's better, to DEFUN within a FLET or to FLET withing a DEFUN? (regarding helper functions which don't depend on parameters)
Stallman · 2017-12-29 21:17
>>5920 (and-let* ((a 10) (b (+ a 10))) b) ; 20 (and-let* ((a nil) (b 10) (c (+ a b))) c) ; NIL It works for me.
roll · 2018-01-01 08:10
>>4844 How does one become a freelance Lisp programmer? It seems to me that's niche as fuarrrk, but I would love to.
Naomi Nascimento · 2018-01-01 09:32
>>5946 Not him but you are either a freelance programmer or not. Your clients won't tell you what language to use (most of the time) as long as the software you produce archives its purpose and is compatible with the already existing software.
Von Neumann · 2018-01-01 17:03
>>5947 A more general question: what sorts of projects can a freelance programmer expect to find? I'm guessing there's some web work, but what other projects are small enough to just assign to a single guy to implement by himself over the period of a few weeks/months?
Acid Burn · 2018-01-01 19:29
>>5949 Usually it will be some sub-project. Either you are brought in as a general code monkey to help with whatever is needed (dont, bad pay) or you are brought in as a specialist for something that your client has not enough knowledge in. I am for example a freelance cryptography consultant. So naturally I usually do the parts of a bigger project that are related to cryptography or security. Sometimes I dont even do that, I just consult and assign the parts to be programmed to other employees or freelancers. I.e. I halp the client determine that their 3DES module is outdated and that we should change it to a AES-GCM one. I explain why and how, what other alternatives there would be to that and if needed I do workshops and talks to train the future users of the system (not in this case). Actually implementing the new module (aka. calling the correct functions from a library file) can then be done by someone else.
John Titor · 2018-01-02 08:09
The Plague · 2018-01-02 14:51
>>5926 Thanks, I didn't know macros were so good that you could recurse with them. ; (and-let* (($ a 20) 'ayy (evenp (random a))) ; (progn ...)) (defmacro and-let* (clauses &body body) (let ((first (first clauses))) (cond ((null clauses) `(progn ,@body)) ((or (atom first) (not (eq (car first) '$))) `(when ,first (and-let* ,(rest clauses) ,@body))) (t `(let (,(cdr first)) (when ,(cadr first) (and-let* ,(rest clauses) ,@body)))))))
St. IGNUcius · 2018-01-02 21:30
> (case #'car (#'car 'works)) => nil why, doesn't it use EQL
Acid Burn · 2018-01-02 22:07
Wondering if SBCL structures are O(1) in getting and setting
Incognito · 2018-01-03 04:01
>>5966 Since #'car is the designator in the clause, it is never actually evaluated.
Tequila · 2018-01-03 15:13
>>5972 wait, im confused, explane more please
Delilah · 2018-01-03 16:33
>>5978 Consider: (case 'foo (foo 'bar)) ; BAR (case 'foo ((foo buzz) 'bar)) ; BAR The key (called a designator), in this case FOO, is left unevaluated by CASE. If it is a list, then CASE tests if the key is EQL to any member of the list. Recall that #’CAR expands to (function car). In your case, this is (basically) what CASE is actually going to test: (or (eql (function car) (quote function)) (eql (function car) (quote car))) ; NIL We can observe this behavior in other ways: (case 'function (#'car 'works)) ; WORKS (case 'car (#'car 'works)) ; WORKS (eval `(case #'car (,#'car 'works))) ; WORKS You don't want to use CASE for this. Use COND instead, or write your own macro with the desired behavior.
Unspecified · 2018-01-03 22:22
>>5980 Thank you very much.
Crazy Jake · 2018-01-04 09:17
Ok, this is probably quite a stupid Emacs question. But here we go. So, I started my lisp adventures with SICP, using MIT-scheme and the default mode in Emacs. Now that opened a REPL and evaluated the code in that REPL. Then I started looking into Racket, the Geiser mode, common lisp and SLIME. But those emacs modes would print the evaluations in the minibuffer. Question is, can you give me a couple of pointers on were to look so when I C-x C-e the expresion prints in the REPL that starts up rather than in the minibuffer? Second question, I just don't get why printing stuff in the minibuffer is comfy, I like to have a log of what is going on, so I can quickly check whether what I am doing is correct. Is there something I am not getting? Or am I just not supposed to use the minibuffer?
Neuromancer · 2018-01-04 21:51
>>5989 I'm not sure about printing everything in the REPL, but any previous minibuffer messages can be found in the *messages* buffer, if you need to check them again.
Mitnick · 2018-01-05 08:38
>>5992 Yeah, that is what I have been using. But its not a really pretty buffer, is it? Thanks for answering anyways :)
Cereal Killer · 2018-01-05 20:53
Hi there. I'm a total Lisp noob. Is it OK to ask somebody to review this code, which is probably an eyesore and very un-idiomatic? It grabs all PDF files from any given thread. I've been reading a lot of tutorials on Lisp and I absolutely love it, but I didn't realize how hard it is to wrap one's mind around the Lisp way until I tried actually writing a short program. (ql:quickload '(:dexador :plump :lquery :lparallel :cl-ppcre)) (defvar *already-downloaded* nil) ;; I think this function is not needed, but good practice I guess. (defun is-downloaded (name) (if (member name *already-downloaded* :test #'string=) t (progn (push name *already-downloaded*) nil))) (defun filter-pdfs (lst) (remove-if-not (lambda (el) (and (string= (subseq el (- (length el) 3) (length el)) "pdf") (equal (char el 0) #\/))) lst)) (defun fetch-urls (url) (let ((request (dex:get url)) (content nil)) (setq content (plump:parse request)) (lquery:$ content ".fileinfo a" (attr :href)))) (defun append-domain (lst domain) (map 'vector (lambda (el) (concatenate 'string domain el)) lst)) (defun extract-name (url) (let ((slash-pos (position #\/ url :from-end t))) (subseq url (+ slash-pos 1) (length url)))) (let ((urls ()) (names ())) (setf lparallel:*kernel* (lparallel:make-kernel 8)) (setf urls (append-domain (filter-pdfs (fetch-urls "https://www.lainchan.org/%CE%BB/res/2730.html")) "https://lainchan.org")) (setf names (map 'vector #'extract-name urls)) (lparallel:pmap nil (lambda (url name) (unless (is-downloaded name) (format t "Downloading ~a...~%" name) (handler-case (dex:fetch (cl-ppcre:regex-replace-all "λ" url "%CE%BB") name :if-exists :supersede) (error (condition) (format t "~a failed: ~a~%" name condition))))) urls names)) Thank you.
Bob Arctor · 2018-01-05 22:58
>>6012 (1) Is lisp, we typically name predicates MYPREDICATEP or, if we hyphenate the name, MY-PREDICATE-P. So, IS-DOWNLOADED should idiomatically be named something like DOWNLOADEDP (2) IS-DOWNLOADED is doing too many things because it also is responsible for updating the *ALREADY-DOWNLOADED* sequence. Try to keep IS-DOWNLOADED side-effect free, meaning that its calls shouldn’t modify any state. (3) In FETCH-URLS you `setq` content. You should either bind CONTENT in a LET*, or (which I strongly recommend) remove the CONTENT variable completely. i.e. (defun fetch-urls (url) (let ((request (dex:get url))) (lquery:$ (plump:parse request) ".fileinfo a" (attr :href)))) (4) Consider in EXTRACT-NAME using regex to find the appropriate URL field, if possible. (5) You SETF both URLS and NAMES instead of providing an initial binding. You should bind both in the LET expression and avoid using SETF. (6) This is the most serious problem. You are using PMAP to apply an operation (IS-DOWNLOADED) that is destructive. Consequently, the use of PUSH introduces a race-condition in your code. To correct this, consider the following approaches: (a) Use a mutex to protect access to *ALREADY-DOWNLOADED* (b) Redesign the program to use queues for inter-thread communication Since your program is so small, I would recommend just using approach (a). (7) For the finished product, wrap the download behavior into a single function. (8) I prefer to use the #’(LAMBDA …) syntax rather than vanilla (LAMBDA …), but this is personal. Now, onto things that you did well :) - nice job using external libraries. No need to reinvent everything from scratch! You probably have good experience in another language, or you have picked up on a good habit early. - your function names generally indicate the behavior of your functions, and each one (aside from IS-DOWNLOADED) performs a single piece of work. I haven’t run your code, but I believe it works, and I can easily understand what the desired behavior of each function is. Nice readability and overall organization.
HELIOS · 2018-01-06 02:14
I have bordeaux threads in my CL program that loop forever . How do I make them stop without the system giving me memory errors? I tried to bind the thread maker withing a let which has a binding with symbol die, and the thread stops once I (setf die t) and it reads die to be t This is all done using with-lock-held macro each time But that also gives me errors What do I do?
Hopper · 2018-01-06 08:40
>>6013 Thank you a lot for checking it out. I do have a followup question regarding #5. When I need two variables where the value of one depends on the other (names needs urls to be filled in first), can I use a single let (do bindings evaluate in order and are available right away), or do I need to use two nested lets, so that in binding names I can use the value of urls? What I mean is, can I use the bindings as I'm defining them? (let ((urls stuff) (names (extractnames urls)) ...) Also, are #'(LAMBDA ...) and (LAMBDA ...) 100% equivalent? What is the reasoning behind this choice?
Technician · 2018-01-06 13:49
>>6016 If you need to bind A and then B, you can't do that using vanilla LET. Fortunately, this use-case is very common and so there is a macro LET* that provides this behavior. For example: (let* ((a 1) (b (1+ a))) b) ; 2 It is generally considered to be bad form to use LET* unless you actually need the sequential binding behavior, so don't go overboard. >are #'(LAMBDA ...) and (LAMBDA ...) 100% equivalent? Basically. There's some small behavioral differences that usually don't matter that you should read up on. Generally, we prefer #'(LAMBDA ...) for coherence. Most idiomatic lisp that you see will use this form.
Tank · 2018-01-06 14:08
>>6016 Also, you can avoid using any global state (i.e. remove the *ALREADY-DOWNLOADED* sequence) if you just remove duplicates from the NAMES list. That way, you can encapsulate this program's behavior into a single function (i.e. DOWNLOAD-THREAD) and put this in a nice ASDF system. Then, you can reuse this system for any future projects without any potential problems. To do this, just modify your code like: (let* ((urls (append-domain (filter-pdfs (fetch-urls "https://www.lainchan.org/%CE%BB/res/2730.html")) "https://lainchan.org")) (names (remove-duplicates (map 'vector #'extract-names urls) :test #'string=))) ...)
Unspecified · 2018-01-07 16:50
Hello lispers! I'm looking to learn programming, and i have a poor mathematical background. I am unemployed as of now and I might start school again, to fix up my grades and relearn some math. Is HTDP2e a good start for me?
Ein · 2018-01-07 23:23
I love programming, but when I write Lisp I feel like I'm doing some sort of magic. I don't know exactly why, but it's a very enjoyable language.
FILLER · 2018-01-08 01:46
Is it possible to make the constructor defined by a defstruct be able to &allow-other-keys?
Spike Spiegel · 2018-01-08 02:48
>>6032 >going to school Stop. Don't go to college and most importantly don't get yourself into any kind of debt by falling for the student loan scam. Study by yourself by reading books and abuse open access course work from places like MIT.
Bypel · 2018-01-09 12:56
>>6036 That may be because you are influenced to think that way by the culture here. Do you think?
Drano · 2018-01-11 09:43
Hey lainons, I'm working through SICP, I'm on exercise 1.16 where you're told to write a iterative procedure using successive square to calculate exponents in logarithmic time. (this sounds bad ass) I wrote the following but I can't tell if it is actually a iterative process because of the way odd exponents are handled. It doesn't seem like it would be a recursive process either though because it only has the single extra * x waiting to be executed with odd numbers. Would someone mind telling me? Thanks. (define (^ x y) (expt x y x)) (define (expt x y z) (cond ((= y 1) z) ((even? y) (expt x (/ y 2) (* z z))) (else (* x (expt x (- y 1) z)))))
Joey · 2018-01-11 17:33
>>6077 Sorry it was 5 in the morning and I hadn't gone to sleep when I wrote that. The state isn't contained in variables so it isn't iterative correct? for the sake of completion this is what I changed it to: (define (^ x y) (expt x y x)) (define (expt x y z) (cond ((= y 1) z) ((< y 2) (* x z)) (else (expt x (/ y 2) (* z z)))))
⍕ · 2018-01-11 21:44
>>6077 >>6101 I believe you are right. Its hard to read tho, given the poor formatting. But yea, if you are not expanding a tree, and then collapsing, the algorithm is iterative (or tail recursive)
The Oracle · 2018-01-11 22:41
>>6104 Yah sorry about that, because I was just typing out my answers in REPL and it doesn't seem to support the tab key for some reason I didn't realize I wasn't formatting well. I went back through all my exercises and redid the formatting. Thanks for responding lainon.
Torvalds · 2018-01-12 07:48
>>6077 This, like you noticed, is definitely not iterative. The else clause expt call cannot be tail-call optimized, since you need to remember the value of x until after the recursive call returns, so that you can multiply through by it. >>6101 This is now tail recursive, but it isn't a correct solution to your problem. Check the value of (^ 10 6). Also, try allowing for 0th powers to be computed as well.
setq · 2018-01-12 15:31
>>6106 No biggie. I would recommend you use emacs and type stuff in the source buffer. that makes working with lisp extremely easy.
t · 2018-01-12 18:12
I'm going through ANSI Common Lisp and I have a doubt. Are these two equivalent? Why? (defmacro nil! (x) (list 'setf x nil)) (defmacro nil! (x) '(setf x nil)) Thanks.
Zhora · 2018-01-12 18:16
>>6121 OK, I know why they aren't. In the second case the x would be quoted and we don't want that. (defmacro nil! (x) `(setf ,x nil)) Would be the equivalent. I should've kept reading before I asked!
byte · 2018-01-12 19:22
>>6115 >>6119 OK hopefully this is the last version :P This is my first real attempt at programming and should probably be in the beginner thread, sorry. I returned to the first version considering the second one didn't even work, and I just started by multiplying a new variable by x when it was odd, and simplified. I plugged in some pretty massive numbers and it seems to work. :D (define (^ x y) (expt 1 y x)) (define (expt x y z) (cond ((= y 0) x) ((even? y) (expt x (/ y 2) (* z z))) (else (expt (* z x) (- y 1) z)) ) )
Tequila · 2018-01-12 21:52
>>6124 x^0 = 1 and not x
Joey · 2018-01-12 22:35
>>6127 it just looks funny because of the way I wrote it, it does respond 1 for x^0
Special Agent Bob · 2018-01-13 19:57
Does anyone know of a way to do this in scheme? (define-record foo bar) (let ((obj (make-foo 'nani))) (with-foo obj (print bar) ;; prints "nani" (set! bar 'desu)) (print (foo-bar obj))) ;; prints "desu" Records are useful to consolidate state, which makes my code cleaner and helps me separate presentation from data, but the record getters and setters are often annoying and long. I'm writing in Chicken Scheme, but I guess I could port a macro from another Scheme.
Hopper · 2018-01-13 20:06
>>6140 I guess to clarify my query, I'm looking for a way to, in a with- form, access the members of a record with just the field names for those members. I could do this in haskell using some transformer, I think maybe runST.
Nemissa · 2018-01-17 23:32
[code] lisp (defun flatten (list) (reduce (lambda (x acc) (if (atom x) (cons x acc) (append (flatten x) acc))) list :initial-value '() :from-end t)) (defun distribute (deck &key (players 2)) (labels ((distribute (deck hands) (cond ((null deck) hands) (t (distribute (nthcdr players deck) (mapcar #'cons deck hands)))))) (distribute deck (make-list players)))) [code] Why does my distribute function only work with players equals 2 or 4?
() · 2018-01-20 13:36
what is the most intuitive and easy book on Common Lisp my gents?
Nanashi No Gombe · 2018-01-20 15:56
>>6311 Practical Common Lisp
Mitnick · 2018-01-24 05:57
>>6140 >>6141 So I went ahead and figured this out. It's ugly but it seems to work ok. It uses some convenience bits from http://wiki.call-cc.org/eggref/4/basic-macros. It wouldn't surprise me if there's a much better way to approach this, but I'm not great with macros. (define-for-syntax (concat-bits #!rest bits) (string->symbol (string-concatenate bits))) (define-er-macro (define-record* x % c) (let [(name (cadr x)) (slots (cddr x))] `(,%begin (,%define-record ,name ,@slots) (,%define-er-macro (,(concat-bits "with-" (symbol->string name)) x_ % c_) (,%let ((,%name ,(symbol->string name)) (,%slots (,%list ,@(map symbol->string slots))) (,%rec (,%cadr x_)) (,%body (,%cddr x_))) `(,%let (,@(,%map (,%lambda (,%slot) `(,(,%string->symbol ,%slot) (,(,%concat-bits ,%name "-" ,%slot) ,,%rec))) ,%slots)) ,@,%body)))))) (define-record* foo bar bazz) (define f (make-foo 1 2)) (with-foo f (print (list bar bazz))) ;; => (1 2)
Bob Arctor · 2018-01-24 07:15
>>6381 I guess I should add this breaks for compiled Chicken code I gave it a good go anyway
Spooky · 2018-01-24 23:59
For practice I wanted to try rewriting some of my silly bash scripts in guile. Things that find and download all the music files from a given domain, etc. Converting to SXML and going from there is easy and great, but I can't figure out how to download a websites source in the first place... I don't know what to search for to help me - Maybe I'm just thinking about this all wrong. Are there internet downloading modules I should know about and be using, am I supposed to be making external calls to wget, or what?
Masami Eiri · 2018-01-25 10:17
>>6399 If you want to rewrite shell scripts you might want to look at Scsh instead, it's a Scheme with lots of primitives to help you write shell scripts.
Miho Iwakura · 2018-01-25 18:12
I want to fully learn pretty printing with Common Lisp? Are there any literature for this?
let · 2018-01-27 17:10
>>6414 >I want to fully learn pretty printing with Common Lisp? >Are there any literature for this? Yes. You'd do good to read this, §22.2 The Lisp Pretty Printer: http://clhs.lisp.se/Body/22_b.htm From my thoughts on it, pretty printing is something that's usually done well enough to ignore; I don't use the pretty printing interface manually much, but it's certainly useful to be familiar with and, like the rest of Common Lisp, it seems well designed, although I should read this to refamiliarize myself with it, as well. It's one of those parts that's easy to forget about if you don't use it much.
Bobby Newmark · 2018-01-27 22:48
>>6434 I tried to read that but it was confusing. I ended up trying to read the actual source but its outdated. Looks like I'm going to have to do with #'FORMAT
Hououin Kyouma · 2018-01-28 09:27
>>6440 >I tried to read that but it was confusing. Well, which parts did you find confusing? >I ended up trying to read the actual source but its outdated. I'll assume you mean the dead link. >Looks like I'm going to have to do with #'FORMAT The FORMAT directives simply call the pretty printing functions.
drdr · 2018-01-28 20:25
>>4793 >>5336 >My hypothesis is that your Lisp environment is going to read the array literal #(#\a #\b #\c) as the most general type possible (i.e. SIMPLE-VECTOR). I do not believe this is specified by the standard, but I can't find any information about it. it is specified, and your hypothesis is not right. the main differentiator is element-type of the array. #( is not a general purpose array reader, it's a designator for simple-vector, and a vector is simple vector, when it's element type is t. in order for it to be a string its element type needs to be character or its subtype. details in http://www.lispworks.com/documentation/HyperSpec/Body/02_dhc.htm and http://www.lispworks.com/documentation/HyperSpec/Body/15_abb.htm and http://www.lispworks.com/documentation/HyperSpec/Body/26_glo_s.htm#simple_vector so when you do #(...) you're always getting an element-type t. but when you do (make-array ...) later, you request element-type to be base-char, thus explicitly specializing the array. random fact: some lisps extend #A macro to allow inline element-type, but that's non standard. in cmucl for example you can enter #A(character (3) (#\a #\b #\c)) to get same "abc".
drdr · 2018-01-28 20:29
>>6454 oh yeah, a simple demo of my explanation is (array-element-type "abc") gives BASE-CHAR, while (array-element-type #(#\a #\b #\c)) gives T
drdr · 2018-01-28 20:57
>>5754 common lisp is a kind of union of various lisp machine lisps, it's actually missing a bunch of convenience functionality that each vendor was already providing at the time. in the modern days of soykaf libraries and code reuse, modern lisp vendors try not to provide custom non-standard utllity functions so you're instead stuck with least common denominator functionality out of the box, and hundreds of utility libraries instead.
Iverson · 2018-02-04 00:04
I found a game where a genie teaches you scheme. It requires JavaScript. http://eblong.com/zarf/zweb/lists/
Hitomi · 2018-02-06 01:15
>>4920 Would you mind posting the source for the game? I am curious to see how it works. Thanks in advance