5 ms·
The very beauty and reason behind filter is in that it does not care about its arguments. It is a logical construct - if predicate is satisfied - keep it. The
by lngnmn 10y ago
The very beauty and reason behind filter is in that it does not care about its arguments. It is a logical construct - if predicate is satisfied - keep it.
The ADTs, type-tagging, predicate logic and duck-typing are superior and less cluttered than homogeneous box-like variables and restricted homogeneous conditionals are - the cost of static typing.
Yes, one could shot himself in the foot, but one also could run instead of crawl.
- renesd 10y agoQuack, quack. I'm a duck.
- mannykannot 10y agoSometimes it is more important to not shoot oneself in the foot than it is to run. These discussions always end up with two antagonistic camps, so let's acknowledge that we can choose the degree of language support, in keeping a program's semantics as intended, according to the circumstances. Language selection is an aspect of engineering judgement.
- lngnmn 10y agoBut I nevertheless would argue that this (item for item in iterable if predicate(item)) is vastly superior idiom and the principles behind dynamically-typed languages, which makes this idiom possible, are sound. filter(P, []) -> []; filter(P, [H|T]) -> filter(P(H), H, P, T). filter(true, H, P, T) -> [H|filter(P, T)]; filter(false, H, P, T) -> filter(P, T). Look, ma, no IFs
- coldtea 10y ago>is vastly superior idiom What makes it superior? Just that is appears more generic? It actually isn't. As long as it's passed an object for iterable that's not iterable it will break. At runtime. As long as it's passed an item inside an iterable that's not compatible with the testing predicate makes, it will fail. At run time. The only reason it looks more generic is that it does LESS.
- lngnmn 10y agoIt not "appears", it is generic. As generic as it could be. This particular line is also a generator comprehension which produces a lazy sequence. Run-time errors and so-called null-propagation are well-known issues and once code passed unit tests it is no less trustworthy in principle than statically-typed one. In the first run, yes, there is a chance of a run-time error. The dynamic languages, notably Lisps, Erlang, Python and Ruby are proved to be superior for quick prototyping and so-called exploratory programming, which has been popularized by pg, along with bottom-up design and the layered-DSLs architecture, in the OnLisp book. Another classic example is Norvig's Design Patterns in Dynamic Languages which basically ridiculed the whole thing. There are distinct cultures around MIT Scheme and Common Lisp, Smalltalk and now Python which emphasize expressiveness, minimalism and readability. Such an erudite like you should know this.
- coldtea 10y ago>It not "appears", it is generic. As generic as it could be Only in the sense that accepting arguments that it shouldn't accept and it'll crash with, is part of the general description of the filtering operation -- which is not. If you prefer, it's "more generic" than it should be. It's not a generic description of the "filter" operation, but a generic description of the "process_input_and_produce_output" operation. >The dynamic languages, notably Lisps, Erlang, Python and Ruby are proved to be superior for quick prototyping and so-called exploratory programming Where is that proof published? And what methodology did it follow? Since, you know, we are computer SCIENTISTS and all...
- lngnmn 10y ago> what methodology did it follow? http://erlang.org/download/armstrong_thesis_2003.pdf http://norvig.com/java-lisp.html http://arclanguage.org/ http://old.ycombinator.com/viaweb/ Yes, 'proved' was a too strong claim. A few exceptionally good systems has been produced, notably Symbolics CL, Smalltalk, Erlang and Clojure, which after removing all the hype and snowflakery, is a remarkable thing.
- 10y ago
- cormacrelf 10y agoThis is more a comparison between Python and functional programming than dynamic vs static. This is partly because the language you compared it to is Erlang, which is a dynamically typed language, with no compile-time checking. But also because you can do this superior idiom in statically typed languages if they offer it, and you also get the static type checking. In statically typed C# with LINQ, you can have, generic over T: IEnumerable<T> iterable = ...; var filtered = from item in iterable select item where Predicate(item); This does not depend on the static typing. It's just syntax. One non-obvious difference is that the type checker knows that 'filtered' must be an IEnumerable<T>, and you can't accidentally treat it as an IQueryable<T> or an IList<T>, which have subtly different behaviour. You can't, for instance, attempt to sort an IEnumerable without getting it ToList() from it. This is good, because enumerables can be lazy, and lists can't. Python checks the enumerable/list distinction, but only at runtime. So let's say your Python library offered a method returning a list, and a new version of the library did some filtering before it returned the list. A test for that functionality might pass independent of the distinction, because what test case attempts to sort a list for no reason? Some other part of your code used to work on the old version, but now breaks, and nobody knows until they run their program or write a really comprehensive test suite. In comparison, in C#, this problem literally never arises, for one of two reasons: 1. The API initially offered only an IEnumerable<T> and consumers were calling .ToList() before sorting anyway (which is free on an IEnumerable that's actually an IList); or 2. The library author catches the error when it doesn't compile, because you can't implicitly downcast IEnumerable to IList.
- lngnmn 10y agoWhy you are ignoring the fact that one have to type so much less for the same result? ;) Filter is the canonical example of a truly generic function. Suppose I wish to filter out something from a stream or a port. Then all I shall do is to supply a generic predicate, which only matches what it is supposed to be a predicate of and ignores everything else. This is what a predicate is - a matcher for some category. So, quickly writing something like (filter this? (filter (lambda (x) ...) ...)) without even thinking about type signatures is what dynamic languages and type-tagging are all about - quick prototyping. This is related to the embedding-of-DSLs technique and producing a systems which are layered DSLs instead on a common big ball of mud in Java. Shall I cite from OnLisp or arc.arc and news.arc? ;)