http://en.wikipedia.org/wiki/Array_programming
its also important to note that this is syntactic sugar - and like most kinds of syntactic sugar it can make code confusing to read, in order to make it prettier. being explicit is often a very good thing for readability and for compilers (they must also read your code) - i value it highly.
although there is something nice about being able to add two arrays together and it do 'what i would expect'... but what do i expect if the arrays do not match in size? how much more thinking do i need to do over being explicit?
Array programming is due for a renaissance. Like any other form of abstraction, we gain leverage once we are able to internalize it and use it. The thinking you mention is, I think, just the normal hurdle of unfamiliarity.
i lean heavily towards code being explicit - i think of black boxes and third party libraries as things to grudgingly use because i don't have superhuman productivity for instance, and i prefer if i can debug their internals... i know this is not entirely common.
name.trim.filter{ _.length != 0 }.toUpperCase
becomes: name >>= (return . trim) >>= (guard . ((/= 0) . length)) >>= (return . toUpperCase)
I've purposefully used >>= and return instead of fmap to show that '.' above is almost >>=.EDIT: I've just noticed a type error in the use of guard, but you get the idea.
do
n <- name
let trimmed = trim n
guard (length trimmed /= 0)
return (toUpperCase trimmed)This would seem to be a problem in general, and a particular problem for nested collections. Explicitness makes intent clear.
Each operator defines its extent. The count operator '#' in J works at the top level. If you have a 3 x 4 matrix, it returns 3. Take '{.' works the same way. If you have a 3 x 4 matrix and you take 1, you will get a 4 element vector which is the first row of the matrix.
Something like decrement '<:' applies to all of the elements in a matrix regardless of the dimensionality.
This isn't like OO where collections have operations attached to them.
val upper = for {
name <- request getParameter "name"
trimmed <- Some(name.trim)
upper <- Some(trimmed.toUpperCase) if trimmed.length != 0
} yield upper
println(upper getOrElse "")
In Scala, an implementation of flatMap (bind), map, and filter allows you to use for expressions like the above. Objects that support these operations are not strictly monads, but they're close enough for most practical uses. Haskell is great, but give Scala a little credit.In addition to APL and J, that would look a lot like SQL as well.
(Though SQL often uses nullable values rather than a collection-like type for the use case where Scala uses Option types -- so the specific example used at the head of the article might look similar in SQL, but not because SQL is an example of the general approach the article is discussing.)
I think an explicit "map" is more flexible in a general-purpose language. Some languages do interesting experiments with this, e.g. Perl6 which uses “hyperoperators” to precisely control how a given operator is applied.
http://en.m.wikibooks.org/wiki/Haskell/Understanding_monads/...
Bind is concatMap and return puts something into a singleton list. This allows "nondeterministic" computations, where applying functions over all elements in the list is implicit (via bind). Using the monad is not the same as having map be implicit everywhere, but it allows cases where you need several chained implicit (concat)maps to be cleanly implemented.
This is arguably a better design than making all functions polymorphic over lists, and having implicit maps be a global rule (rather than something constrained in a monad's context).
let x = Just 3 in
do
value <- x
guard (value > 1)
return (value * 4)
If x was 'Nothing' then the whole operation would short circuit and 'Nothing' would be returned. If the guard fails, then 'Nothing' is returned.So e.g. `read` is a generator that reads lines from the input, `write` writes a line to output, and the composition of them, `write(read())`, is a generator that copies lines from input to output. To run the generator, you can write `while write(read())`.