345 karma · joined October 25, 2010
Otherwise this concept is fine. I'd love to see Wikipedia reset in Meta Serif or Tisa at 66-72 characters-per-line.
A lot of folks are asking for a demo and, you're right. I should have included one. My apologies. I'll get to working on one as soon as I can.
In the meantime, I encourage readers to check out the source for http://www.nytimes.com/interactive/2014/02/02/fashion/red-ca... That's probably the clearest "demo" of PourOver at the moment.
More to come!
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-}
class Concatable a b where concat' :: a -> b -> a
instance Concatable [a] a where concat' l xs = l ++ [xs]
instance Concatable [a] [a] where concat' l xs = l ++ xs
a :: [Int] a = [1,2,3]
b :: Int b = 4
c :: [Int] c = [4]
-- Main> concat' a b
-- [1,2,3,4]
-- Main> concat' a c
-- [1,2,3,4]
As you your other point though, about general problem solving, I think I was unclear. When I said you miss the loops and divide-and-conquers of everyday life, I was just trying -- perhaps too lyrically for my own good -- that you are unable to categorize the world into categories you do not know and cannot recognize. You can't see that the operation you do for every page could be abstracted into a loop, exectuable by a computer. You don't see that you don't need to compare all of your friends to arrange them by height, say for a sweet picture, but you can quicksort them. (Ok this is about as contrived as you can get but programmers have a hard time thinking of places most people don't see programming but we do. Because we see it everywhere).
Finally, sure we should focus on illiteracy, debt, oppression etc. We are working, though, on a lot of these problems programmatically.
1. Don't we all learn physics? At least basically in school we learn about inertia and atoms and velocity. Sure we don't learn the hard stuff and our understanding is woefully incomplete. But the analogy would be "the physics we learn in school" and "things like conditionals, sets, graphs, types". 2. The utility curve of physics is a little different than that of programming. Both contextualize the world and give you richer understandings of it in a similar fashion. However, physics stops solving everyday problems sooner than programming does. I have never whipped out alternative spacetime topologies to solve an everyday problem. I have written tons of bots and things to automate my life.
Dunno, just some thoughts.
"That which interests us in a given situation, that which we are likely to grasp in it first, is the side by which it can respond to a tendency or a need. But a need goes straight to the resemblance or quality; it cares little for individual differences. To this discernment of the useful we may surmise that the perception of animals is, in most cases, confined." - Bergson from Matter and Memory
Constraints on what we broadly know and understand are constraints on our contact and perception of the world. We can't live in a digital world and be blind to the recursions and graphs in the furniture.
So we have languages that compile to JS that let the language evolve. I use CoffeeScript sometimes and JS sometimes. I'm not going to waste the time in the write-compile CoffeeScript loop for 100 lines of JS that I can write correctly. However, I no longer have to work on a 2k LOC, complex JS app without all the niceties of CoffeeScript. Furthermore, if I'm doing something that benefits from the special expressivity of a Lisp, I'll use clojurescript. If I'm very adventurous (and I need to write, say, an H.264 decoder), I'll use emscripten after any language that compiles to LLVM first.
But these are all for different uses, often things you would never have used POJS for anyway. It's not a discussion of plain ol' JS versions of H.264 encoders vs those made originally with Emscripten. It's a discussion of them not existing at all before, and now having the ability to express them and compile to JS. It's not a question of the old enormous apps we built in JS to the new, simpler ones we express in CoffeeScript. It's a question of not being able to build/maintain 5k LOC in POJS across many developers (whereas this task is less substantial in CoffeeScript). Live and let live and everyone benefits.
None of the proposed object-lockdown would prevent anything. You could use decorators, you could use an adapter, hell you could rewrite or fork the useful library and take out the object-locks. But all of those introduce the very overhead that JS benefits from avoiding. I mean compare the size of "Javascript Pattern" to the GOF book. What's more, languages like Java are written with a sensitivity toward design patterning, Haskell has robust types/interfaces. Javascript just has a big empty box, prototypes and closures. (This is an exaggeration but if you declaim it loudly enough you will get a chuckle.)
That being said, I think it is - wait for it - premature to call NoSQL an unwarranted early "optimization." For our real-time analytics app, we use Redis because we are just storing key (page name) value (hits). With millions of writes a day for relatively simple data, it is nice - and in no way premature - to run Redis on a medium-sized instance. Data retrieval is fast and after a year and a half we haven't had any problems.
Other apps, use MySQL exclusively. For our many-many forests of tag, entry, source, author, etc etc relational data, we rely on the easy oversight of MySQL and the rich ORMs that have gracefully evolved to cut through the jungle.
What's more, there are many applications that use both Redis and MySQL. My Silver gem https://github.com/tpm/silver wraps MySQL requests in a Redis caching layer to speed up queries. This is not terribly novel or that different than, say, memcached but it does what we need it to.
The point is that just like apps are as multiform as the imagination is competent, so should be the tools and strategies we use to create them and solve their problems. Yes, people will use NoSQL incorrectly. People use MySQL incorrectly and inefficiently more than not. Hell, you can use YAML in a bad way. Those aren't the cases we should focus on. We should focus on all the systems that do work.
I'd like to see, for every mind-thinky post about whether or not MySQL is a death trap or NoSQL is a nu-wave panacea, a post about how some company is making the technologies that they have chosen work for them. At the end of the day, there is no uniform march toward optimal global technology efficiency. Just the small victories of a startup that needs to record cat GPS movements, a newspaper that needs to analyze a million pages of leaks, a broker who needs to pour through SEC dumps. NoSQL, NewSQL, SQL, HithertoUnknownUnPostSQL: I say let em all in. Someone will find them useful.
Also, there's not, so much, another layer between frontend and backend as there is a multiplication of frontends. It certainly may get us into trouble. Luckily, we already were in trouble and, worse case scenario, we all learn a lot from the experience.
The hell-road blacktop is something we are trying to tear us by substituting the abstract relation of CMS to site for a closer isomorphy of app to function. Who knows? Might work.
And that is why startups are rarely successful.
Pattern matching/data extraction: Both Haskell and Scala have powerful pattern matching capabilities for extracting data from complex types in a simple and clear fashion. However, do to some of Scala's OO features such as case classes and extractors, elaborate pattern matching can be set up quite elegantly. A good example of this in action is the lift-json library that allows users to query a large JSON object in a variety of ways (LINQ,Xpath,etc) and decompose it swiftly. Haskell's pattern matching is accomplished through it's data constructors. This leads to simpler pattern matching on small structures but can quickly devolve into spaghetti with increasingly complex structures.
2. Laziness: Haskell wins this round as most of Haskell's types are lazy by default and you have to work hard to make them strict. In Scala, laziness is accomplished through either the Stream type of Collection views. Say for instance you have a 1000 item list, map 2 functions in succession that can't be composited and then return some arbitrary numbers of initial elements (perhaps a convoluted example) this is how you would do it in Haskell (this is not how you should ever write this but say, for the sake of argument you had to):
take 3 $ map (\a -> a * 10) $ map (\a -> a+1) [1..]
As you can see, this automatically had to happen lazily as it was performed against an infinite list. Compare the same thing in Scala:
List.range(1,1000000).view.map(_+1).map(_ * 10).take(3).force
For the sake of presentation, we just used a long list for the Scala example. If you want to check the laziness, try do this with the view and force and watch how long it takes. We could have also done this with Streams but we will look at this in the next point.
3. Infinite lists. Once you work with infinite lists in Haskell, you will want to use them all the time. In Haskell you just write, say,
take 3 [1..]
to make an list of all positive integers and take the first 3.
In Scala:
def posints(a:Int): Stream[Int] = a #:: posints(a+1)
posints(1).take(3).force
Now, why these three examples of things easier in one or the other? I think that they exemplify the real difference between Haskell and Scala: In Scala, complex things are easier and easy things are more complex. In Haskell, easy things are easy and complex things are complex. This is, of course, a gross oversimplification and there are many caveats: Haskell does functional stuff easier, Scala does mixed paradigm stuff well, etc. Whatever. Every explanation is an oversimplifcation of something more organic.
I would be happy to post more example of differences between Haskell and Scala. They are both so rad.