807 karma · joined October 19, 2016
(defmacro let (bindings &body body)
`((lambda ,(mapcar #'first bindings) ,@body)
,@(mapcar #'second bindings)))
Seeing it use MAPCAR like that just made something click for me for whatever reason.I could agree that a high coverage score is a prerequisite for having confidence that your test suite is comprehensive (in general), but that's such a low bar, it's like saying a full bath is a prerequisite for a nice house, just knowing that shouldn't do much to convince you it's a mansion.
Coverage tools could only measure quality of a test suite if you're assuming that either the code is perfect or that the existing tests cover (logically) everything about what they test. Without either of those guarantees, it doesn't tell you anything very meaningful, as you discovered.
I disagree; what spectrum are those on opposite ends of? Encapsulation, polymorphism, and inheritance are entirely compatible with FP, and immutability is entirely compatible with OOP. Functions and objects are equivalent. Most mainstream OO culture is centred around procedural programming, but it's the procedural parts that oppose a functional style, not the OO parts.
edit: Oh, right, destructuring, too! I guess that also counts.
Out of curiosity, how would you feel about a macro like this (ignoring that it doesn't enforce any keyword order)?
(defmacro for (var &key = (then =) while do)
`(do ((,var ,= ,then))
((not ,while))
,do))The general shape of a LOOP expression is just a list of symbols and lists. A complicated LOOP expression that uses many features at once doesn't end up looking very Lispy, but a shorter one like (loop :repeat 10 :do (print 'hello)) shouldn't look at all foreign, especially if you write the keywords as keywords, which many people do.
I guess when people talk about the regularity of Lisp syntax, I think they usually mean that (op ...args) applies the operator OP to the list ARGS. LOOP obeys this very well: the only LOOP syntax I can think of that breaks it is `using (hash-key k)` or with HASH-VALUE. Universally accepted macros break this rule all the time, though. By shoving everything into lists, they totally abandon trying to keep with the (op ...args) form. If you see that regularity as a great advantage of Lisp's, then it seems like you should be much more bothered by the more "mundane" macros than you should be by LOOP.
(loop :for i :below 10 :do (print i))
Is less "syntax-breaking" than: (dotimes (i 10) (print i))Why don't you consider macros like DEFUN, DEFCLASS, COND, etc to be "syntax breaking"?
CL-USER> (defun add (a b) (+ a b))
ADDedit: And your C# version is only 24 non-whitespace characters shorter than the Python version, and 20 of those are because you called your variables 'f' instead of 'filespec' and 'w' instead of 'word'. A 4 non-whitespace character difference makes it exceedingly long and verbose? Or are you just advocating 1-letter variable names and avoiding newlines?
Lisp has plenty of syntax, it's just extensible and largely defined in operators. Commonly used macros like DEFUN, WITH-OPEN-FILE, and LOOP all add their own syntax to the language; that's what macros are for. When you put them together, typical Lisp code ends up looking like
(defun count-words (filespec)
(with-open-file (f filespec)
(loop with counts = (make-hash-table :test 'equal)
for line = (read-line f nil)
while line do
(loop for word in (cl-ppcre:split "\\s+" line) do
(incf (gethash word counts 0)))
finally (return counts))))
Which I don't think is that alien. It translates pretty cleanly into Python: def count_words(filespec):
with open(filespec) as f:
counts = collections.defaultdict(int)
for line in f:
for word in line.split():
counts[word] += 1
return counts
Do you find the former significantly harder to understand? I don't see how
it's any more like "writing a parse tree directly."> Why should I write (+ p 2) when most people think (p+2)? This difference gets worse with more complex expressions.
As mentioned in other comments, there are infix packages available for when you're writing math-heavy code (or if you just need infix operators), but I also think that a lot of people don't write very much code with complicated inline arithmetic in it, and overstate how much the awkward math syntax would affect them (there are of course plenty of projects that are math-heavy and where it does make a large difference). When you're defining variables/functions/classes/etc or calling functions or looping or whatever, there's not much difference between Lisp and most other languages aside from whether the bracket is { or ( and which side of the keyword it goes on; in my experience, that sort of code tends to make up the large bulk of most codebases in most languages.
edit: Another place where Lisp's default syntax is significantly different from a lot of languages is something like object.f(x).g(y).h(z), which in Lisp looks like (h (g (f object x) y) z). This can be remedied with common macros like -> that let you write (-> object (f x) (g y) (h z)).
OCaml does have for and while loops, to be fair, although they don't support break or continue (you can simulate break by throwing in the loop body).
For another example showing their differences, if a.c has:
int n[] = { 1 };
And b.c has: extern int *n;
printf("%d\n", *n);
Then running b.c will segfault, whereas if it said extern int n[], it would work as expected (hint: extern int n and printf("%d\n", n) would also work). Arrays degrade to pointers at the drop of a hat, but they're distinct from them.You start with this, and then go into more examples of "content that was essentially the internet before the internet" like going to 7/11 with friends, reading Nintendo Power, and riding your bike. That sounds a lot more like missing your childhood than any cultural changes, especially when your pre-internet internet includes things like IRC and message boards. It seems like you're just using "internet" as a synonym for "the present".
> All of that greatness is turning to vaporwave nostalgia.
The only criteria for being included in "that greatness" is that you enjoyed it and it's not popular anymore: it isn't turning to nostalgia, it's nostalgia by definition.
Replace Cecil Adams and the Straight Dope with whatever you like, and this is just as fitting of a sappy eulogy.
It was generic "you", the hypothetical person who was having trouble with take home assignments but not interview questions that you were talking about initially. All of my points were about that hypothetical person, and not you personally. Sorry for the misunderstanding.
> My point is fundamentals don't change, frameworks do.
Yes, that's what I was addressing. Companies aren't asking about frameworks when they give you a take home question, they're asking you to learn the framework if need be, which will be easy if you know the fundamentals. I'm not sure where you're getting lost on this point.
What does "otherwise" mean, here? The context we were discussing is that they asked you to quickly pick it up in a take-home assignment, and you couldn't pick it up that quickly. I don't see how this is them being shortsighted; it sounds like you just not delivering on the promise of your "fundamentals".
> the tooling or frameworks change but the core theory does not.
I 100% agree: someone who learnt MVC with Smalltalk in 1979 won't have any trouble picking up Rails' or Django's or whatever's version today. The concepts are timeless.
edit: to boil it down:
> these people should be able to pick up whatever tooling or frameworks on the job.
Yes, and if they can, they won't have trouble picking it up in the process of writing a take-home assignment. If they can't do that, then they just failed a litmus test.
No, I got that. My point was that no one cares that you completed an algorithms and data structures course, they care that you know the fundamentals of (the subgenre they're interested in of) software development. You're just using a definiton of "fundamentals" that excludes the (entirely language and framework independent) concepts they care about that you don't know.
A take home project using a specific language and framework does not require you to know either to complete it before you start; if you know the concepts, you can pick them up as you're writing it. If you've never seen MVC before (and the knowledge you have doesn't allow you to grok it fast), then in a web dev context I would argue that that is a fundamental concept you are missing, which was my point.
Interview questions can be different, but you didn't mention them in the post I responded to.
I think the idea is that you should be able to pick up the language and framework as you go, if you do actually have the concepts down. If your generalised knowledge isn't to the point where you can apply it to some arbitrary framework/codebase in some arbitrary (imperative) language and start being productive more or less immediately (with documentation open in another tab), then your generalised knowledge just isn't at the level where people care about it, yet.
edit: That generalised knowledge they're expecting absolutely might go beyond what you're shown in school (it depends on the school). If you draw the line of "fundamentals" at "what was in my curriculum", then that's an arbitrary line you're drawing, and it's not the line that most of the industry is using (even if people are using their own coursework as their meter). If you consider (eg, in a web dev context) HTTP requests and MVC "fundamental", then you should be able to pick up Rails or Django or whatever without much trouble. Whether or not your school had classes on that doesn't really matter to anyone.
CL-USER> (defun abc-without (letter) (delete letter '(a b c)))
ABC-WITHOUT
CL-USER> (abc-without 'a)
(B C)
CL-USER> (abc-without 'b)
(A C)
CL-USER> (abc-without 'c)
(A)
This behaves strangely because it modifies the constant list (A B C) rather
than consing up a new one on each invocation (like calling LIST or COPY-SEQ
would), so by the end the list it passes to DELETE has been reduced to (A).I don't think the article was saying that AI isn't useful, but just that deep learning specifically is not an AI panacea, and that the current hype around AI is on its way out. The hype dying down and the associated buzzwords starting to repel money instead of attract it is all that's meant by AI winter, I believe, not that we'll run out of places where the techniques would be useful.
She accused him of committing felonious fraud; seeing the doctor respond by giving her her money back and saying "most people don't have a problem" would not cast that doctor in a good light at all, to me. I'm not really sure if there's any kind of response they could have left that would feel reassuring to me: recommending the client contact law enforcement like someone else suggested might help a little, but not that much. The presence of a review with accusations like that that the doctor shrugged off or dealt with casually would be infinitely more offputting to me than hearing the doctor had previously won a libel case against a former client.
This isn't said about the declarative nature of languages so much as it is about the benefits of powerful static type systems, in my experience.
It's quite easy to write Prolog programs that look right (to me, someone who doesn't know Prolog well) but that compile, successfully run to completion, and produce incorrect results (or don't terminate). In Haskell, the compiler actually rejects a huge amount of incorrect programs that I thought were going to work (and the fact that I thought that shows that the declarative nature of the code wasn't sufficient) and then once the typechecker is finally happy, the code often does actually work without further debugging (this is a common experience, and what the saying is referring to, I believe); in Prolog (or dynamically typed functional languages like Scheme), there's very little of that, and I'm left to catch most bugs on my own (even if like you said there won't be as many because they'd be so obvious in the first place).
Prolog might be exceedingly clear once you learn how to read it and it might eliminate errors that way, but "if it compiles, it works" is a terrible description of that. "If it looks right to someone who knows the language well, it works" is much closer, but not as punchy. The entire point of the original saying is that you don't need the experience with the language to get that, because the compiler itself will tell you if you're wrong when your types won't line up.
Scheme isn't, lambda is. That paper is about how lexical closures alone are enough to simulate a lot of imperative concepts like assignment, loops, and gotos (they do cheat and use set! in a couple places, but the point of the paper is how much lambda application can do all on its own). Your broader point about Lisps not being particularly functionally oriented is correct, though; they're some of the most unopinionated languages you could imagine.