14 ms·
A Dead-Simple Web Stack in Haskell
- artfulhippo 7y agoHaskell is extremely complex, and that’s the point: to isolate complexity at the language level, where safe patterns can be researched, developed, and then scaled out to arbitrary applications. Please call this “Towards a simple Haskell web stack” or something else less oxymoronic.
- bojo 7y agoI am going to disagree with this simply because it's talking about the stack, not the language. As a Haskell developer who uses a much more complex stack than provided in the article, and seen too many "there aren't enough basic Haskell web stack tutorials!" posts here and there, I would say the library choices here fit that bill perfectly. That said, once the adventerous non-Haskell user builds a basic application using this stack, they will then run into the brick wall of using a language which you are calling "complex", I would argue "different", and realizing there are a lot of new things they need to learn to actually be productive in it.
- agentultra 7y ago> Haskell is extremely complex I extremely disagree. I think C++ is extremely complex. Haskell is simple by comparison [0]. Once you understand enough Haskell to write basic programs in it this stack is roughly similar in scope to a Ruby + Sinatra or Python + Flask web application. [0] https://www.youtube.com/watch?v=PNRju6_yn3o https://www.youtube.com/watch?v=PNRju6_yn3o
- seagreen 7y agoIt depends on what we mean by Haskell. If we mean "Haskell the latest specification" that's Haskell 2010. I suppose we could think of it as pretty simple, though lazy evaluation means that any implementation of it is going to be complicated. However I don't know of a single company that uses plain Haskell 2010. They all use GHC (or more complex tools like GHCJS!) and GHC Haskell is a beast: https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html https://downloads.haskell.org/~ghc/latest/docs/html/users_gu...
- lalaithion 7y agoAnd how many companies use a C++ standard? GCC and Clang both provide a large number of extensions. https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/C-Extensions.html#C-Extensions https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/C-Extensions.ht... https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/C_002b_002b-Extensions.html#C_002b_002b-Extensions https://gcc.gnu.org/onlinedocs/gcc-4.8.5/gcc/C_002b_002b-Ext...
- seagreen 7y agoOP: haskell is extremely complex. Responder: not it's not (eg C++ is more complex) Me: actually haskell is a complex, beastly language, eg check out the language extensions You: but C++ is more complex! Me: i agree EDIT: Didn't mean to sound snarky, the discussion has just gotten really layered and I wanted to explain my position.
- agentultra 7y agoFair enough there are some combinations of compiler extensions that don't interact well and I've written enough type level code to know which ones to stay away from. The C++ move semantics are standard though and have lots of unintended consequences to make easy-to-describe constructors incredibly difficult to implement in practice. My point was that saying Haskell is extremely complex is not technically correct. It's a qualitative statement and disingenuous. Complex relative to what? The stack the OP is presenting is relatively simple in the Haskell space. It's not inherently complex by virtue of being written in Haskell.
- seagreen 7y ago> It's a qualitative statement and disingenuous. Complex relative to what? Complex relative to most programming languages. C++ is more complex. That says very little. C++ is an extreme outlier. I think Haskellers do a disservice to people they're trying to convince to do haskell by saying it's not complex. Haskell has a zillion extensions and crazy features, most of which show up in at least some popular Hackage libraries. Arrow syntax! Type families! Data kinds! Pattern synonyms! View patterns! Existential types! Rank-N types! The list goes on and on. PS: I think Haskell is awesome and one of the best languages out there. I've written a pretty decent amount of FOSS haskell stuff. Complex doesn't mean bad. EDIT: The complexity doesn't come just through language extensions. The process GHC goes through to produce fast code is crazy too. It works, but it's not simple.
- Symmetry 7y agoI entirely agree about the language itself being a comfortable middle weight, somewhere around the order of Python. But both languages give you a lot of scope to make things complicated and there are much stronger norms against making code as clever as possible in Python than in Haskell. Is there a Pythonic Haskell movement? Because if there isn't there should be.
- weavie 7y agoThere is this great talk 'stick to simple Haskell' along those lines, but unfortunately it is hosted here https://skillsmatter.com/skillscasts/14133-stick-to-simple-haskell https://skillsmatter.com/skillscasts/14133-stick-to-simple-h... Unfortunately I can't find it anywhere else, but it is worth keeping your ears out in case it pops up somewhere..
- leshow 7y agoHaskell 2010 isn't that complex. It's sum and product types and typeclasses, essentially. The many language extensions, depending on what you use, can make for something extremely complex, but you also don't have to do much more than enable them in many situations if you're just a user of a library.
- cousin_it 7y agoI think a simple web stack should aspire to the simplicity of the PHP stack, twenty years ago: 1) Create a directory "foo" on your server 2) Make a file called "bar.php" in that directory 3) Write "Hello World!" in the file 4) Open http://localhost/foo/bar.php http://localhost/foo/bar.php in the browser and see "Hello World!" Lines of code or configuration so far: zero. 5) Add some actual code to bar.php 6) Reload the page and see the result Number of steps to rebuild or restart: zero. Then you can add templating, routing, logging, testing, anything. I'm not married to the PHP language, it's a mess. But the idea of keeping simple things simple is very important, and from what I see of today's developers, that idea has been utterly forgotten. Memory-holed. It's astonishing, I can barely believe that it happened. EDIT: Sorry, I just said this offhand and didn't mean to hijack the discussion. Feel free to downvote, so something more on-topic gets on top.
- nabdab 7y agoI remember fondly those early days with PHP before it dawned on me how many peculiarities it had. However to be fair these steps came only after you’d managed to set up the server which was non-trivial on its own. These days I feel like python/flask does it simpler. True you need to define a function and use a decorator, but saves you having to set up the server before getting started on site itself.
- why-oh-why 7y agoThat sounds like what Zeit.co is doing. Now.sh is nearly zero-config for a static HTML index and any number of functions in many languages under /api/ In their version 1 they actually even looked for index.js in the root and evaluated that one, but now such a thing requires config (and it isn’t even clear on how to achieve it)
- girvo 7y agoI definitely hope this sort of idea takes off: it’s got a lot of promise to eventually take over from PHP for the “get a beginner rendering dynamic content to a browser quickly” use-case, which is how I learned to program 15 years ago!
- 7y ago
- TazeTSchnitzel 7y agoThis is exactly the stack I used when I started building a webapp in Haskell, it was nice. I never finished my webapp though (but that wasn't Haskell's fault).
- bad_user 7y agoI love this. I'm a Haskell newbie, I only do Haskell in my spare time, only sometimes, so I don't have time to hunt around for recipes. Kudos to the author, I'll surely borrow from this. --- I also built a simple web server in Haskell for triggering commands via GitHub's Webhooks [1]. So if you're interested in a very simple, yet useful web app to analyze, see: https://github.com/alexandru/github-webhook-listener https://github.com/alexandru/github-webhook-listener My use-case is to serve a static website using my own VPS, but have Travis build the website (via a static generator) for me. After Travis builds the website via Jekyll, it pushes it to the gh-pages branch, then GitHub pings my server via the installed webhook, which triggers a refresh with the latest build. [1] https://developer.github.com/webhooks/ https://developer.github.com/webhooks/
- ghostwriter 7y agoMigrate your static site to Hakyll https://jaspervdj.be/hakyll/ https://jaspervdj.be/hakyll/ from Jekyll, and use git subtree (http://brittanderson.github.io/posts/2018-01-17-hakyll-and-github-with-subtrees.html http://brittanderson.github.io/posts/2018-01-17-hakyll-and-g...) to publish on GitHub Pages without Travis :)
- verttii 7y agoThis is a great tutorial for getting up and running fast. I started off with Spock too but grew out of it pretty quickly. It's painful in Haskell you're learning it but feel you're not able to generate anything real for the first month(s) with it. Unfortunately, there's not many up-to-date tutorials like these available for beginners.
- dwcnnnghm 7y agoDo you have any recommendations for next steps beyond Spock? I learned Haskell at uni and am interested in going back to it for web work (instead of Erlang). Any insights you might be able to share would be really helpful!
- verttii 7y agoServant. It takes a while to pick it up but it's well worth the effort. You end up with an automatically documented type safe API and you can even generate client functions for other languages using Swagger based on the spec. It has excellent documentation too, the only hard part really is figuring out the handler pattern. As for the SQL story, that's more fragmented. I'm still trying to figure out the best next step myself. I started off with Persistent & Esqueleto but now looking at BEAM, Selda and Squeal for more control over the queries. If you use Persistent as the persistence layer, check out Matt Parsons' blog for a nice intro: https://www.parsonsmatt.org/2016/07/08/servant-persistent_updated.html https://www.parsonsmatt.org/2016/07/08/servant-persistent_up... I'm actually coming from Elixir myself. I have to admit Haskell feels funny at times but admittedly a lot more robust.
- defanor 7y agoNot sure what's meant by "simple" here, but it looks quite complicated to me. Even though I use something similar at work (with Servant), but much simpler (FSVO "simple") approaches as a hobby: - Those frameworks relying on built-in servers, including all their dependencies, are huge. If a program is linked statically (the default for GHC/cabal), that's also a very large codebase that doesn't get updated on system updates. Plain CGI (or FastCGI, if needed) is much more lightweight, and an external web server usually provides generic logging. - postgresql-simple provides more than just protection against SQL injection; that is implemented in the C libpq, and usable with postgresql-libpq bindings (which are used by postgresql-simple) too. - Database connection information, in case of PostgreSQL, doesn't require a fancy configuration: libpq reads it from environment variables. In many cases even those don't have to be set: by default it would try to connect to a local database, under current user, and to the database matching user name. - PostgreSQL itself can compose XML (XHTML/HTML 5), which then can also be processed with XSLT, cutting out the blaze-html dependency. - Custom logging facilities tend to be a pain to work with, and not necessary either; there are syslog and journald. Using all that (and even more) instead of more lightweight/low-level/low-dependency alternatives seems like a sensible compromise in some situations, and I don't mean to say that it's somehow bad, but not seeing how it's "dead-simple". Maybe it's one of those "simple versus easy" cases, or just about different kinds of simplicity.
- ar_lan 7y agoThis reminds me of this commit in Redux: https://github.com/reduxjs/redux/commit/9276ff0af6400633d6731b15fed6e70c3561887e https://github.com/reduxjs/redux/commit/9276ff0af6400633d673.... "Simple" is always a relative term. I agree, if "simple" looks like the complication in the post, then I'm turned off from the language because I don't really want to see what "complex" can become. I have no doubt if I had context of Haskell, I would be able to read that with no trouble - even without Haskell context I think I can grok it pretty well. But imagine a newbie to the industry as a whole? It stops being simple at various stages, very quickly.
- deleted 7y ago[deleted]
- _hardwaregeek 7y agoLet's walk through my thoughts. Hmm, okay so Spock looks nice. Neat! The routing code looks very easy to read: main = do spockCfg <- defaultSpockCfg () PCNoDatabase () runSpock 3000 $ spock spockCfg $ do get root $ do Spock.html "<div>Hello world!</div>" get "users" $ do Spock.json (A.object [ "users" .= users ]) get ("users" <//> var <//> "friends") $ \userID -> do Spock.json (A.object [ "userID" .= (userID :: Int), "friends" .= A.Null ]) Alright, let's figure out how this works. runSpock :: Port -> IO Middleware -> IO () Okay that makes sense. Takes in a port, some middleware and spits out IO. Not crazy. Hmm, okay these dollar signs are making things a little confusing, but I can figure out that spock returns an IO Middleware and therefore we can see that spock takes the output of the right do block along with spockCfg. Not the easiest to scan at first glance because of the right to left reading but okay. Let's look at get. get :: HasRep xs => RouteSpec xs ps ctx conn sess st Ah, okay, so uh...this doesn't appear to be a function. Oh, I see, here it is: type RouteSpec xs ps ctx conn sess st = Path xs ps -> HVectElim xs (SpockActionCtx ctx conn sess st ()) -> SpockCtxM ctx conn sess st () Well I'm not really sure what xs, ps or st are. And HVectElim doesn't tell me anything. Path is pretty clear and SpockCtxM is a monad of sorts. But what the hell is HVectElim? Alright whatever, let's just figure it out via the signatures of Spock.html/Spock.json. Which are...nowhere to be found in the documentation. I looked them up in the index and nope, no entries. I'm very confused about what HVectElim is and why that would be a fine name. I can continue past this point, but you get my gist. This is actually way better than my other experiences with Haskell and web dev, but it's by no means an easy or fun experience reading this code. Variable names like xs, ps, etc. are great when you're dealing with a generic list but they get old when that's the only documentation (because "type signatures are documentation" is totally infallible). And a name like HVectElim is just baffling. What, did they charge you per letter? Did half your keys fall out? Why is that a good name? I really want to use Haskell for something useful. But I'm running into pain points trying to understand a glorified Hello World. Now granted I'm by no means a great Haskell programmer. But that's kind of the point. I understand monads. I get functors and applicatives. I should be able to write a dumb Hello World app dammit.
- defanor 7y agoThat documentation indeed could be improved, but I guess the intention here is that basic usage is learned from the tutorials. Though it's possible to figure from that documentation alone as well (I'm reading it for the first time too, but using Haskell often): Path construction collects types of arguments into xs, then HVectElim (heterogeneous vector eliminator, or maybe "elimination") unwraps it into an appropriate function type. xs are those types, ps is PathState, st usually stands for "state". A dumb web "Hello, world!" can be written with just putStr though, using CGI (along the lines of what I've mentioned in another comment here). Or perhaps with Network.CGI ("cgi" package), which is quite a bit more straightforward than that RouteSpec, especially if one wants to quickly understand how it works. I had a similar experience (wanting to use a language for something useful, but mostly failing to) with Rust, and maybe Python (just s/wanting/having/ in that case), but I guess the problem with that was primarily in trying to find out what's the "right"/idiomatic way to do something while there's none, or to apply practices from other languages. And maybe in not having a suitable project idea at the time. Most likely there can be more reasons of that, but they seem to go away with practice, clear goals, and/or motivation.
- jonny383 7y agoNone of that "web stack" is simple. Literally, none. Am I the only who thinks _every single_ Haskell "developer" suffers a worrying large amount of imposter syndrome? I mean, c'mon. No-one actually cares if you write Haskell or "push lambdas". At the end of the day the only thing that really matter are: 1. Does it run? 2. Is it buggy? 3. Is it cheap? Re-inventing the wheel for no other reason than to hand-wavingly say "look MA I MADE A WEB STACK" is nothing more than masturbation. Haskell is a community of cancerous people that should die, along with cancer.
- smaudet2 7y agoMy take on the whole "complex versus non complex" debate raging below. If there were nothing to the exorbitant complexity, there would be no complaints about modern stacks. It would be sort of, invisible? Like an OS is mostly invisible these days - that problem space is mature to the point that its, for most people, an afterthought. So modern web dev does suck, yes. I am 100% of this opinion. But the simple solution was re-invented into the 'mess' we have today. It doesn't scale (well), and although yes it wasn't complex it was a hell of a lot more complex to add features to, at least ones which weren't simple "hey change the look and feel of some widget" or "hey do some flashy UI thing". I think that's probably a generally true statement, when a lot of work is needed to develop something (physical or otherwise), it will suck, because it still needs to be worked on? So anything being used by the industry and "modern" will have pain points, period. Once its actually good, it tends to be simplified to the point that it becomes invisible. OFC, you can still use WAMP or whatever, or weebly, but nobody cares about WAMP or weebly anymore, outside of whatever small pet project or blog you run.
- Schoon 7y agoTo comment on the choice you have when building your frontend, Reflex/Reflex-Dom also comes to mind.
- asjo 7y agoReally happy to read this - I'm using Spock and postgresql-simple, but found Lucid for generating HTML instead of blaze. I never got around to wrapping my head around handling configuration, so I will definitely take a look at configurator. I also like the suggestions for what libraries to look at next, sometimes choosing what libraries to go for feels like a jungle for a newcomer.