First class citizen functions, short lambdas, comprehension lists, generators, map(), filter(), itertools, operator and functools are quite a rich toolbox already. But you won't have more. It's a choice.
The idea is to have enough to be productive, and not enough to be dogmatic. The experience of Guido, and it's one that I share, is that too much functional tooling drives a style that favors expressive writing at the expense of ease of reading.
It's not by chance that LISP and Haskell are considered hard languages to get into, while Python is considered easy to start with.
It has a cost, since no language is perfect, but that's the path this language follows and requesting a snake to fly will only bring you disappointments.
Python tries to strike the balance between the importance of a rich expressiveness and the non negotiable necessity of keeping the code readable: you read a line much more often that you write it, after all. It's a key philosophy of the language. It shaped and will shape numerous decisions around it.
This PEP is a perfect example : it tooks years for the concept to be integrated in Python, and the last debate about this concrete implementation took months. The result is a carefully crafted feature with a lot of details to discourage abuse and remove the needs for pondering when to use it or not.
and i think you are leaving out functional languages which share python's readability, if not surpass it, while remaining much more expressive. that's f# and ocaml.
f#, in my opinion, is superior in everyway to python and subsumes python's abilities of readability, easiness, oop, and scripting, while greatly raising the ceiling of possibility. it's criminally underused, especially in areas where python has been chosen.
and i disagree lisp is harder to get into. racket is just as easy to learn as python, if not easier, due to its regularity. the how to code / systematic program design course on edX and the book how to design programs showcases this.
The first thing I checked is your very vocal assurance that F# is a better scripting language than Python. That seemed very weird to me, after all it's Python strong point. Since I script a lot, I looked for the most popular F# lib to parse script arguments.
Argu seems the winner, according to http://fsharpworks.com/survey.html. Their tutorial is pretty good (https://fsprojects.github.io/Argu/tutorial.html), and here is their hello world. 24 lines of, packing a dense symbology and using a lot of the specific language features:
open Argu
type CLIArguments =
| Working_Directory of path:string
| Listener of host:string * port:int
| Data of base64:byte[]
| Port of tcp_port:int
| Log_Level of level:int
| Detach
with
interface IArgParserTemplate with
member s.Usage =
match s with
| Working_Directory _ -> "specify a working directory."
| Listener _ -> "specify a listener (hostname : port)."
| Data _ -> "binary data in base64 encoding."
| Port _ -> "specify a primary port."
| Log_Level _ -> "set the log level."
| Detach _ -> "detach daemon from console."
let parser = ArgumentParser.Create<CLIArguments>(programName = "gadget.exe")
let results = parser.Parse [| "--detach" ; "--listener" ; "localhost" ; "8080" |]
printfn "%A" results.GetAllResults();;
The same thing with click, the Python most popular solution, is 11 lines, and it's shaped around almost only regular calls and parameters: import click as cli, base64, urllib.parse as url
@cli.command("gadget.exe")
@cli.option('--working-directory', help='specify a working directory.', type=cli.File('rb'))
@cli.option('--listener', help="specify a listener (hostname : port)", type=url.urlparse)
@cli.option('--data', help='binary data in base64 encoding.', type=base64.b64decode)
@cli.option('--port', help='"specify a working directory.', type=cli.File('rb'))
@cli.option('--log-level', help='set the log level.', type=int)
@cli.option('--detach', is_flag=True, help='detach daemon from console')
def hello(**kwargs):
print(kwargs)
hello(["--detach", "--listener", "localhost:8080"])
I have a hard time finding the motivation to look for the truth behind your other arguments after that.what are your objections? what is the dense symbology?
discriminated unions (what the CLIArguments is) are very simple to define and understand. the usage member nearly uses the simplest possible pattern matching available. pattern matching is a staple of functional languages. it's a case statement in its simplest use but is so much more in general.
these two things are the bread and butter of f#. they may take a modicum more initial effort than simple function calls, but it pays off in readability and expandability. it seems python takes the easy route. it makes things apparently simple at first but difficult in the long run.
i know both languages, to a degree, and find the python hard to read. it's also faking types, which is kind of funny. the f# code is fully typed.
lines of code is meaningless to me here because the f# has better delineation of concepts here.
and lastly, there's actually no reason why you couldn't write an f# library to behave like the python one here. that is not true the other way around. that's the power of f#'s multi-paradigm nature.
i don’t know what you mean. actual argumennts? do you mean like “—working directory” or the values passed by them? i am actually not familiar with this library, but it seems the former is handled by the library from the discriminated union constructor names and the latter are right there in the constructors.
and what do you mena there’s no need? that seems rather arbitrary. it’s a way to represent your data explicitly with types, i.e., is type-driven development.
i can’t further defend this library because i have never used it, but i see no confusion here and don’t even understand the complaints. it seems to be “this is different than how i think in python, so it’s no good”.
Also, click is weird because it wants to take over traditional function syntax and "under the covers" rewrite them. Compared to a much simpler Args -> Map kind of construction, this is a great example of how Python introduces unneeded complexity and prefers to create huge spelunking expeditions into its poorly-explained function invocation syntax & semantics. The PEP we're all commenting around is another great example of that approach. It's too bad Python's community is often more interested in novel uses of Python's semantics than actually readable, reusable concepts.
The irony is other "deep in their own waters" approaches produce stuff that's much more readable than click's without also being some kind of solve-the-universe's-problems black-box. Python dooms itself to that because of its refusal to embrace more composable primitives. They'll always end up with completing big-bang projects that don't play well together. Examples available upon request.
Lbbbx bv bbbbb v
De te. Es. ::: BBC radioThis is absolutely dead on accurate. As a Clojure developer, using one of the most expressive -- dare I say, artistic -- programming languages ever created, I can say that I am totally in the zone writing code which is elegant and terse and really packs a punch, does clever things.... and then just a few days later, it is very hard for my own brain to parse my own code and figure out what it does.
For each line of code you write once, it will be read dozens of times by you or others. Code is for reading. Languages that get this right make things a lot easier for everyone.
The only dogmatic position here is the Python one, that based on opinion alone, and is leaving a lot of good structures out for no gain at all.
It's only because Python is familiar and Haskell is not. Objectively both Haskell and Lisp are dramatically more simple to comprehend than python.
On the other hand, you have a concept which translates easily to any language with first-class functions and lambdas. Even the syntax stays the same among languages which use "f(x,y)" for function evaluation and parameter passing.
/* This post is for those occasions when a list comprehension style is advocated over a functional style, which I know was not necessarily what you were doing in your comment. But I think the two points are valid enough on their own. */
Could you elaborate on that?
> Could you elaborate on that?
It's a very opinionated statement on my part. `if COND then TRUE-CASE else FALSE-CASE` is the correct form to use, in my opinion. Python uses `TRUE-CASE if COND else FALSE-CASE`.
What you are talking about is a different kind of expression, similar to a ternary operator. It is not the same as if...else
> Python uses `TRUE-CASE if COND else FALSE-CASE`.
And this is wrong -- this is not how Python if statements work.
> And this is wrong -- this is not how Python if statements work.
Huh? Didn't you yourself say I was not talking about if statements:
> What you are talking about is a different kind of expression, similar to a ternary operator. It is not the same as if...else
In any case, I'm talking about the case that goes `TRUE-CASE if COND else FALSE-CASE`, as can be deduced from my typing `TRUE-CASE if COND else FALSE-CASE`.
Which shouldn't be that surprising considering originally Netscape were going to port Scheme to their browser before choosing to create a new scripting language with "Java-like syntax" (you can argue amongst yourselves just how Java-like the syntax really is).
Imagine where we'd be if they'd just done that.
Had Scheme been Netscapes scripting language instead of Javascript then I could easily see many of the less dedicated developers and hobbyists getting frustrated at S-expressions and such like. I mean I love functional programming but even I cannot deny that the learning curve is steeper and S-expressions are less readable (at least to an untrained eye) than Javascript is.
So my point was if Javascript didn't exist then I suspect there would be enough demand to either dumbdown / bastardise Scheme, or implement another scripting language which was more hobbyist friendly (also hence the VBScript quip).
+ Just because something isnt "necessary" it doesn't mean it doesn't add value. The problem is just sites that make JS a requirement rather than an optional feature enhancement.
+ Youre talking about stuff from a too recent perspective. Eg Before CSS came into its own, JS was the only reliable way to do mouse over effects (which can add a lot to usability even on regular web pages)
+ Just because JS is abused on current news sites, blogs and other sites that are really just static pages, it doesn't mean that Scheme wouldn't have been abused in the same way.
+ You also wouldn't see fewer developers writing frontend code. They would just use a transpiler (like we see with TypeScript et al) except instead of compiling from a stricter language (in TypeScripts case) it would transpile from a lazier language into a stricter one.
+ Or instead of the previous point (though more likely as well as) you'd still have a non-scheme language in the browser. Possibly even VBScript. Or maybe something derived from Perl. But I guess at least we wouldn't have a language monopoly on browser scripting languages.
Honestly though, I hate JavaScript just as much as you do. But let's not get carried away with our exaggerations :)
Smalltalk also uses ":=" for assignment and "=" for comparison. In Pharo, VA and Dolphin at least does what this Python proposal does - return the value of the last expression.
Python chose a different design trajectory - personally I can't stand it but it certainly follow some sort of internally consistent reason.
The problem is that if you add blocks, then half of the added syntactic features the last decade is redundant as a block version would simply solve the problem a better. Which would create a lot of dead design, and that makes it a bad solution.
Are you maybe conflating blocks with chained iterator operations? Adding blocks to Python's current functional syntax would be pretty ugly. "foo.filter(bar).map(baz)" is nice even if you can only use named functions.
In my opinion the Python's explicit self argument is somehow cleaner approach than having distinct block and function/method types. You still need some kind of ugliness in order to implement super(), but for Python 3 that happens at compile time and the resulting syntax is reasonably sane.
As for the aforementioned method context issue CLOS/MOP takes interesting approach of macroexpanding the method definition into something like
(lambda (args next-method)
(labels
((call-next-method &args)
...
(funcall next-method ...)))
(impl (...)
... method body ...))
(funcall impl args)))
Also of note is that in ST, there are no control structures, even if is implemented as method on Boolean instances which takes block argument, with true and false being instances of True resp. False with different implementations of #ifTrue: method.> preferably only one obvious way of doing it
I don't think that is true at all. Python allows you to perform many tricks, with overloading operators etc.
Pyhton is not really that kind of language.
Python is designed in such a strangly arbitrarily inconsistent, hypocritical and opinionated manner.
Sorry, but it's preposterous to bring up an implementation detail of the standard library that has long been in the process of being fixed. CamelCase was deprecated a long time ago in favour of snake_case; what is left of CC is for backward-compatibility and will eventually disappear. This is all documented.
The standard library is not the language, it's much messier and suffers from all sorts of issues that have nothing to do with the language itself.
from toolz import compose def foo(X):
if bar(foo):
1
FalseFirst of all you have indented 1 and False equally. Is that a typo? Or is it your opinion that the if should always consist of the if and the else branch without using the else keyword?
Secondly, if you want to return a value you need to use the return statement.
Also you wrote bar(foo) but foo was the name of the function, not the name of your parameter.
Perhaps what you are looking for is this:
def foo(x):
return 1 if bar(x) else False (define (foo x)
(if (bar x)
1
#f))
The returned value is the value of the last expression. No need for an else, or a return keyword.It’s fine like that in Scheme and the other Lisps in part because well that’s the way they always did it, but it’s quite different from how it is and has been in Python.
If they want Lisp in Python they should look into Hy.
I don't know what you would lose by having if as an expression. It is easy to notice when it is used in expression context, and there is no extra computation that needs to be done.
It was sort of addressed with the trenary operator, but that quickly becomes ugly.
Well, if you turn if into an expression the way that you indicated then now you will also need the equivalent of the “begin” expression in order to be able to have multiple statements and/or expressions in either branch.
So then you are breaking backwards compatibility. Which makes it a non-starter from the get go.
And like I said there is also the fact that functions need the return keyword in Python if you want to return a value.
Ruby returns the last thing in a method, which I feel is pretty sane.
'foo' if foo else 'bar'