Do I Really Need a Programming Language?
ayudasystems.tumblr.com
ayudasystems.tumblr.com
The grammars exist because programs are made to be read by people, not just computers. A more heterogeneous notation can make for more concise code that's easier to scan and easier to read.
Of course, this is not to say that Lisp is unreadable. I actually rather like reading and writing (paredit is awesome) Lisp code. But, after quite a bit of Racket, I've found that I still heavily prefer having infix operators and a bit more syntax. At the same time, I also often want less noise--ie no parentheses. I want all this so that I can quickly scan and comfortably read my code. That's why we need grammars.
You have not reached Lisp enlightenment yet.
Because you use Emacs, you can get shortcut to enlightenment by choosing color for parentheses that almost hides them to the background.
(I think the fact that SRFI 49 is not more popular might say something, though...)
I want a semantically sane language. What do I care what code Lisp macros can autogenerate if nobody can make sure it makes any damn sense?
Ruby is not semantically sane, it's insane in a way we have all gotten used to. (If you don't know ruby, try to rewrite this for your ALGO language of choice, I picked ruby for its simplicity)
S-expressions are about as semantically sane as you can get, it's just most of us have a <5 year head start with the craziness of c-style languages.
You are talking about syntax here.
> Ruby is not semantically sane, it's insane in a way we have all gotten used to.
I hate Ruby even more. It is just as semantically insane as Lisp, and the syntax is worse.
> (If you don't know ruby, try to rewrite this for your ALGO language of choice, I picked ruby for its simplicity)
Ruby is not simple. It is full of corner cases and redundant constructs. It is hard to make any sort of reasonable guarantee about a Ruby program without resorting to some heavy testing. And no matter what nice property you might have wrestled out of the system, someone else can destroy it anyway by means of monkey patching.
> S-expressions are about as semantically sane as you can get
S-expressions are syntax with no intrinsic semantics.
> it's just most of us have a <5 year head start with the craziness of c-style languages.
What about Haskell? (And, in general, languages that have a denotational semantics that makes equational reasoning feasible.)
For more details, see: https://news.ycombinator.com/item?id=6954348
One of them.
> The best Haskell book I can find is next for me as soon as I finish SICP, any suggestions?
I liked Learn You a Haskell for Great Good, but that is maybe just because I am a childish person. :-)
Both are available online for free!
Explicitly, in lisp, everything is a stack of instructions arranged in a tree. The instructions are either functions that manipulate the input data, or functions that manipulate the underlying tree of instructions.
By naming convention and documentation, we give the various functions semantics. ("With" macros being an example).
I was just refuting the assertion that "S-expressions are about as semantically sane as you can get".
> Explicitly, in lisp, everything is a stack of instructions arranged in a tree.
I do not particularly care what data structure is internally used. That is the compiler's business, not mine. I want to reason about my code in terms of the semantics of the language I am using.
> By naming convention and documentation, we give the various functions semantics. ("With" macros being an example).
Names may be misleading, documentation may be incomplete, but types never fail to accurately guarantee properties about my code. Hence my preference for types.
His comment was equally nonsensical. S-expressions are consistent and easy to parse, that is all.
> I do not particularly care what data structure is internally used. That is the compiler's business, not mine. I want to reason about my code in terms of the semantics of the language I am using.
>I do not particularly care what data structure is internally used. That is the compiler's business, not mine. I want to reason about my code in terms of the semantics of the language I am using.
Good, that data structure generally isn't used internally in the compiler (not efficient enough). I'm talking about the data structure that is used for the programmer's brain. The semantics and way of reasoning about the code is in terms of a very simple data-structure.
My business is the compiler's business.
> Names may be misleading, documentation may be incomplete, but types never fail to accurately guarantee properties about my code. Hence my preference for types.
Why would you write such shitty code? There are many ways of skinning that cat. You can use types, you can use tests, you can use assertions.
You could make it overly complicated and long. A stupid person is going to have a bad time writing code, no matter what language you hand them. Shitty code is shitty. This is a tautology comparing the language I'm currently into to a language I'm not currently into. Don't use it. You're good at writing Haskell, good for you.
def add(x, y):
return x + y
(define (add x y)
(+ x y))
These are similar semantically -- they each define a procedure that takes two parameters, adds them, and returns that result. Hand-waving how the language is actually implemented, they're morally equivalent, anyway. But syntactically they're fairly different.Another example: https://en.wikipedia.org/wiki/Colorless_green_ideas_sleep_fu.... That sentence is semantically meaningless, but it has the correct syntax.
edit: fixed code formatting.
But in the reality using macros is no more complicated than using functions.
[1] http://www.ai.mit.edu/projects/iiip/doc/CommonLISP/HyperSpec...
[2] http://www.common-lisp.net/project/slime/doc/html/Macro_002d...
Do I have any guarantee that the resulting macro-expanded code semantically makes sense? (e.g., a guarantee that it will typecheck)
(my-macro (2 + 2))
and output valid lisp code during macro expansion time. The macro my-macro could expand the code to something like: (+ 2 2)
Some Lisp compilers such as CMUCL will issue a warning if you try to use wrong type (it has type inference), such as in this simple example: (defmacro foo ()
`(+ 1 "foo"))
(defun bar ()
(foo))
You can see the compiler notes here: http://imgur.com/3vlQm6GAs for macros, they are merely functions that transform expressions. They can be somewhat unpleasant to read, but they are basically that.
Unityping. Now every useful function is automatically not total!
> I find it has very clean semantics; it is strongly typed
Of course it is strongly typed! All expressions have type Univ.
> programs are commonly written in a way that preserves referential transparency
All my C++ programs are commonly written in a way that preserves referential transparency, and clearly distinguishes between objects that are meant to be mutated (non-const) from those that are not meant to (const). That still does not make C++ a pleasant language to program in.
> The limited dynamic scope may be somewhat unpleasant though, but that's its flexibility.
Spooky action at a distance. Me no like. :-(
> As for macros, they are merely functions that transform expressions. They can be somewhat unpleasant to read, but they are basically that.
Will the result typecheck?
> Of course it is strongly typed! All expressions have type Univ.
Have you used PHP? You'll come to appreciate the differences between the different "unityped" languages.
> All my C++ programs are commonly written in a way that preserves referential transparency, and clearly distinguishes between objects that are meant to be mutated (non-const) from those that are not meant to (const). That still does not make C++ a pleasant language to program in.
Does that say anything about Lisp? Nope, not at all. It isn't like C++ is comparable to Lisp, despite the efforts put by C++ programmers to wrest safety from a language designed as a superset of the language of cowboy-coders par excellence, its true nature as an imperative language with raw pointers may rear its head at any point. Not to say that Lisp has had more facilities up to this point than C++ to write referentially transparent programs.
> Spooky action at a distance. Me no like. :-(
Depends on the Lisp. Common Lisp's global variables are mutable and dynamic. Me no like either. In Racket and Clojure you can declare variables to be explicitly dynamic, and they can be rebound within special blocks, locally, sort of. Not that it's something anyone should use frequently.
> Will the result typecheck?
Does the if keyword typecheck?
Autolisp does not typecheck.
And that's why I prefer Forth syntax
But yes, you're always going to have a grammar. Albeit simple, you need a tokenizer/parser for lisp and forth. It's simple, but it is there.
Computers don't know what 2.345 or "blah" means, we still need a way of inputting this in a friendly way.
$ rebol
>> price: 99
== 99
>> either price > 100 [10] [5]
== 5
>> ;;; and even more interesting is...
>> ten: [10]
== [10]
>> five: [5]
== [5]
>> either price > 100 ten five
== 5> Should I revisit it again some day?
I'm probably not the best person to ask here because I've only come across Rebol in last 12 months. I've had great fun playing with it and have used it for a few small scripts/projects.
The current pros would be:
- Rebol3 is now opensourced (since 12-12-2012)
- Rebol3 is faster than Rebol2 (in my simple tests about twice as fast) & with smaller footprint.
- Rebol3 comes with some design improvements, for eg. 64-bit integers, module system, async schemes & more.
However the cons are:
- Rebol3 still in alpha/beta development.
- So not all features of Rebol2 are (yet) present in Rebol3.
- Rebol3 GUI is only available for Windows & Android at this moment.
So depending on your use case then you may find yourself still needing to use Rebol2.
If you code in Ruby, Python, or Coffeescript, yeah, lisp has more parens, no doubt. That is the price of its regularity. Lisp could throw all that out the window, but you'd lose the easy macros.
Edit: added the link
In terms of syntax, I think there's a divide between the needs of static type-systems, versus dynamic ones. LISP is at its core a dynamic language. It makes sense to treat code as being data that can be manipulated. Getting rid of all that syntax gives you great power in terms of what you can do. And personally I find Clojure code to be much saner than code written in Ruby or Python, but that's another discussion.
However, the other side of the coin are Haskell or Miranda (its predecessor) or languages in the ML family or Scala. These languages go to great length to achieve much of LISP's expressiveness, while ensuring a great amount of static type-enforcement. Haskell is especially notable because Haskell is lazy and has many goodies, such as type-classes or rank-2 types. People say that when a piece of Haskell code successfully compiles it is usually correct. LISP can't do this, even though there have been experiments with pluggable type-systems.
For an excellent rant on the choice of Scheme for SICP (and not Miranda, Haskell's predecessor), checkout: http://www.cs.kent.ac.uk/people/staff/dat/miranda/wadler87.p...
So IMHO, syntax helps if you want static type-safety, because the language and the type-system exposed need to be expressive. Whether static type-safety is useful or not, it's a matter of debate, being highly dependent on the problem domain. One could argue that static type-safety is very useful if the shape of the data you're manipulating is well defined and doesn't change much, otherwise you're better off with a dynamic language, but that's another discussion.
Type systems fall squarely in the "semantics, not syntax" department.
Every time I see this claim, I wonder what the heck people are working on that is so simple that getting the types right is all it takes to get the code right? Is it just that enough of my work is math or parsing, both of which typically have an infinite number of ways to get things wrong but with the correct types?
Or is the idea really the other way around -- if your program is sufficiently complex, you'll never get it to actually pass Haskell's type checks?
Edited to add, I love the article you linked to so far. :)
Sometimes I got a type error from some bizzare syntax mistake, usually failing to correctly delineate an expression, and sometimes the algorithm in my head was just wrong and I had to fix it. At that point, the cycle starts over, and the same benefits I mentioned above help in debugging. FWIW, the problem I was working on was fairly simple, but novel. I was a very happy camper this Christmas, working with OCaml, despite its syntax.
Out of curiosity, what language do you do your "math and parsing" in? OCaml might be a good fit.
To give a somewhat extreme example of the sort of stuff I do -- one of my current projects is to try to create a first-class fillet surface type [1] for the geometry engines I work with. My current code converts each fillet to a NURBS surface, but this is slow, consumes a lot of memory, and produces surfaces which frequently are not accurate enough for my purposes. So my hope is to be able to directly calculate points on the fillet and their derivatives.
It's easy enough to calculate points on the fillet surface, but I don't see any obvious way of directly calculating the derivative along the surface. So I've been investigating Chebyshev polynomials in two variables. But that algorithm looks a bit hairy, and I don't have any feel for whether it will be an actual improvement in practice. (And having written all this, I'm suddenly wondering if I'm making every effort to sort out the simple cases that are easy to solve exactly.)
My point here is that figuring out the correct types involved seems like a tiny, tiny part of the required work. Maybe it's because I haven't put in enough time in Haskell, but I don't see how stricter than C++ types are going to help. The real work is getting the math correct and fast enough to be useful.
By the way, my comment is not meant to be a dig at Haskell (et al). I'm not sold on it as a language, but it certainly has a lot of interesting ideas -- pattern matching and laziness spring to mind.
For domains outside of physics and applied math, I think the dominating factor is often the inherent trickiness of writing correct procedural code vs. the ease of writing strongly typed functional code.
Pattern matching is at least as much fun as it looks like, if you have complicated data types. That's a lot of what made OCaml so perfectly match my problem.
[0] https://github.com/andrewf/apatch if you're curious. The meat is in patch.ml
Why can't Lisp do this? In the Common Lisp world, there's some pretty aggressive, though still optional, static type checking. There's also Qi, Shen, Typed Racket, et cetera. The question is orthogonal to the question of syntax.
For example, how would you type the cons function? In Haskell, it has type t -> [t] -> [t] (i.e., for all types t, given a value of type t and a value of type list of t it produces a value of type list of t). In Lisp, on the other hand, you can construct a cons cell out of any two objects.
Obviously you can certainly construct a type system in which you can handle Lisp cons cells reasonably; Hindley-Milner type systems aren't the only game in town. But I don't think it'd have the 'if it compiles it probably works' property any more.
A more useful question is the following: "is a simple grammar the be-all and end-all of programming language design?". I think the answer is "no". Ceteris paribus, a simpler grammar is of course to be preferred to a complex grammar. But, ultimately, people write programs for what they do (so that they can be useful) and for what they mean (so that they can be maintainable), not for how they look like. So a simple semantics takes precedence over a simple syntax.
> Of course, this is not to say that Lisp is unreadable. I actually rather like reading and writing (paredit is awesome) Lisp code. But, after quite a bit of Racket, I've found that I still heavily prefer having infix operators and a bit more syntax.
That is precisely what languages like Haskell (and to a lesser extent ML) give you: a typed lambda calculus (semantic simplicity) with infix operators (syntactic eye candy) for convenience. The type system reduces the universe of valid programs to those that typecheck, so you do not have to worry about stuff like the meaning of 2 + "potato".
As Wittgenstein remarked, many philosophical conundrums arise from the odd results that follow from using ordinary language in an odd way.
Wrong. Just because a language A is implemented by means of a translation into language B or execution by a machine C, it does not mean that A's abstractions do not exist at all. If A makes guarantees B or C cannot possibly make, then A will compile to a strict subset of B or yield a strict subset of the processes that can happen in C. In this strict subset, A's guarantees hold.
(5 . * . 3) ; 15
(5 . > . 3) ; #t
As a bonus, you even get more verbose syntax as in other languages, because Racket, being a Lisp will let you write code any old which way so long as there is a macro available to parse it.#I( x^^2 + y^^2 )
And, naturally, you can macroexpand the macro.
[1] ftp://ftp.cs.cmu.edu/user/ai/lang/lisp/code/syntax/infix/infix.cl
> I actually rather like...
> I've found that I still heavily prefer...
> I also often want...
> I want all this so that I can...
...
> That's why we need grammars.
Well, that was a twist ending.I actually find those harder to read. Generally, because I can indent Lisp code however the heck I like, I have a pretty good idea what's going on just from looking at the structure of the code and reading a few words here and there.
It's a fairly common experience for me in other languages to be scanning back and forth across a line searching for that $%^$£%£ operator rather than (in the rare event I get really lost in a Lisp file) just going, "Highlight the next s-expression up, ah that's what's going on." Or "You know what? Indent my code for me in a different way."
I wonder whether there's a divide between people who understand code initially by looking at the structure and people who understand code initially by looking at the operators in terms of who likes Lisp :/
Anyway, it's interesting that he chose to label what he ended up with as "Lisp". I would've stopped at assembly, eg. in LLVM IR:
%result = icmp gt i8 %price, 100
br i1 %result, label %Discount1, label %Discount2
Discount1:
ret i8 10
Discount2:
ret i8 5
The key idea here is that underneath everything you tell the computer to do is boolean logic and transistor circuits. Yes, even Lisp S-exprs; it's not really correct to say "Lisp has no syntax", it has a very simple syntax that is trivially parseable. Even LLVM assembly is a translation layer, as is LLVM itself; underneath it on my computer is an i86 processor, and underneath it in my phone is an ARM-architecture Snapdragon.Once you understand that, you realize that all of these languages and frameworks and libraries and databases are just tools, and they exist for your convenience. They're there to let computers handle things that humans are really bad at. For example, memorizing memory layouts really sucks; let a computer map out your structs onto memory. Managing heap memory really sucks; let a garbage collector do it. Managing register allocation really sucks; let a compiler do it. Managing syntax kind of sucks; let a parser slap something more friendly on top of it, or don't and use Lisp. Managing vtables kind of sucks; let C++ or Java hide it behind a class, or don't and continue to use C.
Once you've gotten into this mindset, you're free from the religious wars that surround technologies, because you realize it's all just tools that compile down to machine code at the end. And you understand when a tool might be useful, and when you could just as easily implement it yourself, and when it once was useful but has since ceased to be.
That seems all fine and well, but you're ignoring the elephant in the room: compatibility. You aren't free to choose your tools as you please if compatibility is one of your requirements. This little bit of impurity combines with network effects to create big problems. Compatibility along with all its attendant problems is the single most valid reason for engaging in a religious war over technology.
Personally, I take a different one: the computer exists to run my code. LLVM, x86, ARM... all just implementation details. Sometimes they're unavoidable, but c'est la vie.
Ultimately, what I care about is semantics. I care about what my program means--the logic it represents. After all, that's the whole point, the end goal. The fact that it's running on a physical computer is just a detail, albeit an important one.
A programming language is more about shaping my thoughts and forming my logic than actually running. Choosing a programming language is incredibly important--it affects what I can say, how I can say it and even how I think. And that's the most important part.
The original task was "apply a seasonal rebate to our products," but none of the programs actually accomplished this feat. They contained some logic which might be useful in such a program, but none of them applied anything. Logic on its own is sterile.
When I'm in my algorithms class and we have a code snippet to find a minimum spanning tree, we don't even have some machine to compile it down to, but because we have denoted some meaning to bit of the program, we can even prove that the meaning of the entire program is to output the MST.
> What is a program? Several answers are possible. We can view the program as what turns the general-purpose computer into a special-purpose symbol manipulator, and does so without the need to change a single wire (This was an enormous improvement over machines with problem-dependent wiring panels.) I prefer to describe it the other way round: the program is an abstract symbol manipulator, which can be turned into a concrete one by supplying a computer to it. After all, it is no longer the purpose of programs to instruct our machines; these days, it is the purpose of machines to execute our programs.
EWD1036
otherwise we would just compile and decompile into each form. intermediates like lvm come close to trying to do this i think? not sure if they allow going back to the original form from the IL though.
oh, and lastly, think of trying to express a feature in 1 high level language with another that doesn't support that feature. it's quite hard to gain expression when it's not idiomatic in that language.
kind of similar to spoken language actually. some concepts in some languages form as single words or phrases that never really translate well to other spoken languages because the place that other language formed never had that concept.
The point of a programming language is making complex stuff readable. One can certainly hand-assemble and write software as a series of byte values and I have done so in the past because of necessity. It's very boring and difficult.
In this respect, I don't find Lisp readable or intuitive at all, but that's just me, I'm probably not smart enough:-)
Everyone? For starters, I would exclude those studying law, medicine, most of the 'soft' sciences, and probably chemistry and physics, too.
Yes, most of these might be better of having some knowledge of programming, but I doubt they really need to know what a parse tree is. Hand-waving "3+2x6" is three plus (two times six), just as in normal life" probably is sufficient for most of them. Even math majors need not know about compilers and machine architecture.
That leaves a tiny fragment of 'everyone in college': just the computer science students and, to a lesser degree, the software engineering ones. I would present the latter to parse trees, but I would not go in any depth there. Really, for most people doing software engineering, compilers can be black boxes.
Except they're not.
Only the simplest ASTs are directly translatable. Language semantics differ wildly when you get into higher level constructs. Not even Lisp is able to help you, as that just changes the problem from one of syntactic representation into one of library implementation.
At least that's what I think this is about, and Lisp is a good GCD.
x + 1 => -2147483648 (Java)
x + 1 => Undefined behaviour (C, assuming int32_t and various things about the implementation)
(1+ x) => 2147483648.0 (Emacs Lisp)
(1+ x) => 2147483648 (Common Lisp)
x + 1 => x + 1 (Prolog, using some interpretive license)That said, I think it's possible to invent a language in which all the things you mention can be expressed and at least compared. I'll do my best to do it myself if no one beats me to it. Any language with closures is close. Java inner classes and (AFAIK) C# lambdas practically are clsoures. If the only thing ruby blocks add is that returns and similar statements affect the block-creating function, that can be simulated with exceptions.
The question should really be, why does the IT department care if he uses C or Basic? And more over, why did he try to make it in C in the first place if he knows the IT department prefer Basic? This is a case of unprofessional behaviour by the author, not whether or not you need a language to express an if statement. At that point he could just as well have written this is x86. Who needs maintainability anyway?
Here I would pick up the article and write this:
No matter which language I start with, the end result is always the same. So maybe I could simply write out what is important for me:
if price > 100
10
else
5
And then I realized I was coding in CoffeeScript.It has a wonderful technical elegance, but the humans that have to write code tend to not think in the same sense. After four or five brace levels it gets very challenging to keep track of everything.
cmp eax, 100
jle LESSTHAN
mv 10, edx
ret
LESSTHAN:
mv 5, edx
ret
I doubt that's what the author had in mind, though. return price > 100 ? 10 : 5;83 f8 64 7e 06 ba 0a 00 00 00 c3 ba 05 00 00 00 c3
Or even :
10000011 11111000 01100100 01111110 00000110 10111010 00001010 00000000 00000000 00000000 11000011 10111010 00000101 00000000 00000000 00000000 11000011
I'd do better still, but I lost my butterfly somewhere.
>If you understand how compilers work, what's really going on is not so much that Lisp has a strange syntax as that Lisp has no syntax. You write programs in the parse trees that get generated within the compiler when other languages are parsed.
In that sense, the LISP syntax (S-expressions) were ideed designed as an intermediate language, not to be used by programmers directly (except for plain data structures).
(car
(append
'(a b c)
'(d e f)))
Would originally have been written in M-expression form as car[append[(a b c); (d e f)]]
Programming in Lisp might be a very different experience if M-expressions had caught on!So...
Ruby: good for developers, bad for the JIT compiler (slow)
LISP: awful for developers, good for the compiler -> machine (fast)
Is the tradeoff worth it? Not at all. Most LISP intros start by convincing you that you'll eventually get used to your code looking like a sack of parenthesis. No thanks, I shouldn't need to get used to staring at overburdened verbosity for the compilers' sake - build something better. Wait..we have other languages that are fast and look nice. And many even process into a well-formed AST. Okay, thank heavens.
Only Python comes close IMHO but has many other downsides.
(incf (elt vector 2)) ..versus.. ++vector[2]
which one is more readable?
LISP is not to be taken seriously. It's an academic curiosity, and cute, novel, not a language that needs continued zealots. It has no market share..the reasons are always going to be the same. The language is esoteric. I wouldn't program anything serious in JSON so why would I use LISP, where every semantic is a list..not even a hashmap.
http://imgs.xkcd.com/comics/lisp_cycles.png
"These are your fathers' parenthesis"
One reason I like Lisp is that I don't have to think about operator precedence.
In LISP: (+ (* a (1+ (* 8 b b))) (* 4 b c (1+ (* 4 b b))))
Oh, that silly operator precedence, lets just jam our heads in a vice while we unravel the nesting.
I'm not quite sure whether it is just plain trolling or traumatic experiences with Lisp at college. (The latter which I can understand since being allowed to only use a very limited part of the language to solve convoluted problems can be quite off-putting.)
It also makes it easier for YOU to process/manipulate your program with the expressive power and safety of the full language.
http://en.wikipedia.org/wiki/Homoiconic#Uses.2C_advantages.2...
LISP is great for live audio production because of the homoiconicity. It's very suited for dynamic interactive programming, namely Emacs. I believe that's where the zealousness needs to stop. It's not a good language to code large projects in.
It's pretty funny that the knee-jerk dismissals of Lisp today are the precise opposite of what they used to be.
That's what we mean when we say you write directly in parse-trees. You're writing the string representation of those parse-trees.
Alternately: If I augment Python by letting you surround a block of Python code with curly braces in order to get an object representing the corresponding AST, does that mean that I can write Python directly in parse trees? :P
But the fact that the Read phase can be usefully separated from the Eval phase is a distinguishing feature of Lisp, and why it makes sense to say, at least, that Lisp has no concrete syntax, only abstract syntax. Lisp programmers fluently think in terms of the abstract syntax their code generates, because they read and write in the string representation of that abstract syntax. That's why it makes sense for the Lisp eval function, unlike the eval function in other dynamic languages, to take lists as input rather than strings. That's why a metacircular interpreter in Lisp will be written to input lists. That's why a DSL in Lisp written as a custom evaluation function will be an interpreter for lists. The Lisp language is defined with respect to the list data-structure, rather than strings.
On your Python idea: the problem is that no-one would ever use Python code as the literal representation of Python's abstract syntax.
It would be entirely backward, anyway. Lisp starts as a notation for a data-structure rich enough to represent abstract syntax (symbolic expressions) and then defines a language in terms of this data structure. The philosophy of this is understood when we realise that the roots of Lisp are in metalanguages and logic.
return ( (price > 100) ? 10 : 5);
Computer languages are for people. It should really be more like this:
#
# Description of what this does.
#
PRICE-THRESHOLD = 100
LOWER-PRICE = 5
UPPER-PRICE = 10
IF PRICE > PRICE-THRESHOLD RETURN UPPER-PRICE
ELSE RETURN LOWER-PRICE
Alternatively, use Excel: =IF( (price > 100), 10, 5 )
Excel is cryptic, but a lot of finance people understand it. if (price > 100)
return 10;
else
return 5;
Replace with more named variables if you want. return price > 100 ? 10 : 5;
is way more readable.(iirc)
* Greenspun's 10th rule of programming: "Any sufficiently complicated C or Fortran program contains an ad-hoc, informally-specified, bug-ridden, slow implementation of half of CommonLisp." http://c2.com/cgi/wiki?GreenspunsTenthRuleOfProgramming
* James Gosling quoting Guy Steele: "Lisp is a Black Hole: if you try to design something that's not Lisp, but like Lisp, you'll find that the gravitational forces on the design will suck it into the Black Hole, and it will become Lisp". http://web.archive.org/web/20091201072950/http://blogs.sun.c...
This video is relevant. Amazing talk.
Here is an example (write out 1 2 4 8 16 32 on different lines):
Application (
using Library ( name "Vision.Console" )
action ForEach (
items 1 2 4 8 16 32
action WriteLine ( text CurrentItem () )
)
)
Parts are upper case and properties are lower case.
Each Part is a class 1 contained within a given framework.They never quite got around to making M-expressions though, people found working in S-expressions to be pretty fine.
Dylan is sort of a compromise around this area though:
http://en.wikipedia.org/wiki/Dylan_(programming_language)#Sy...
I am not used to Lisp or VB.net but I do find the first two examples a lot more readable.
(Seasoned Lispers, does reading Lisp get easier to read over time? As readable as an imperative language?)
(price > 100) * 5 + 5;
yay! no branching!That said, I'm always looking for the least branchy way of doing things.
ISO/IEC 9899:1999, 6.5.8, p6 has this to say:
"Each of the operators < (less than), > (greater than), <= (less than or equal to), and >= (greater than or equal to) shall yield 1 if the specified relation is true and 0 if it is false. The result has type int."
cmp price, 100
setg reg
movzx reg, reg
lea reg, [reg + reg*4 + 5] cmp price, 100
cmc
salc
and al, 5
add al, 5
6 bytes not including comparison. "You don't get into the demoscene, the demoscene gets into you." :)(Neat.)
Here you go, simple integer math, no programming necessary :) That said, this isn't optimisation, multiplication and division aren't intrinsically better than branching.
if (price == 100){ ...Your solution fails when price == 100 as sibling pointed out.
Ahhh the fundamentals!
In Python:
a = 3 * 4 + 5
In Lisp:
(setf a (+ 5 (* 3 4)))
Now maybe it's just me, but balancing all those parentheses and thinking in prefix notation gets a little hairy, especially if we introduce more math into a program (think graphics or ML).
3 7
- + -
4 8
Can't write that in Python. Looks like Python does not support even basic math notation.Lisp does not even attempt to do that.
We have to write
(+ (/ 3 4)
(/ 7 8))
or (+ 3/7 7/8)
Let's say we want to write a slightly more complicated expression in Python: 2 2 +-+ 3+-+3+-------+2 3+-+2 3+-------+
- 2b x \|3 log(\|a \|b x + a + \|a \|b x + a + a)
+
2 2 +-+ 3+-+2 3+-------+
4b x \|3 log(\|a \|b x + a - a)
+
+-+3+-+2 3+-------+ +-+
2 2 2\|3 \|a \|b x + a + a\|3 +-+3+-+3+-------+2
12b x atan(----------------------------) + (12b x - 9a)\|3 \|a \|b x + a
3a
/
2 2 +-+3+-+
18a x \|3 \|a
Not possible. It does not know basic math format for roots, exponents, ... Lisp also does not know it.Balancing parentheses in Lisp is usually done with the help of an editor...
a = 3/4 + 5/8
than
(setf a (+ (/ 3 4) (/ 7 8)))
and the primary problem that I have with the parentheses not closing them, but logically seeing how expressions link together. Even if you can click on an end paren and see the expression it closes off (as you can in most IDEs) it would be easier just to not have the extra parentheses there in the first place, so as to avoid the confusion.
It's really hard for me to even tell what you're trying to write for the second part -- in Python or Lisp.
(setf a (+ (/ 3 4) (/ 7 8)))
I have no problem writing or reading that.Personally I like the parentheses a lot, since they allow me comfortable editing operations for such expressions. Additionally it makes it easy to computationally manipulate those expressions as data.
Without him, they will spend most of their lives on mindless debates sucking their creative energy like a vampire blood.