In the 1990s I did research on the efficacy claims of object oriented programming versus procedural programming. This article bares a striking resemblance in the claims. Case study after case study showed that object oriented code had less bugs due to compilers catching bugs, etc. However, almost every study was similar to this report: it was a re-write from procedural to object-oriented. There exists strong evidence to suggest that throwing away ones first prototype produces the same results as to benefits comparing object-oriented versus procedural programming. The conclusion of my research was the same as others: unless one is comparing the same project written from scratch without any sharing of design or code then these studies claims are correlation, not causation.
There's a lot of truth in that. A few days ago I wrote a comment about rewriting a program from C++ to C and coming in at about 1/4th the code size. However, I didn't mention C or C++ in that comment because the real savings came from reevaluating requirements, lessons learned, refactoring, et al.
Some time back, someone here on HN posted a comment about rewriting a Java app in... Java. Same basic story of large savings, without changing language at all.
Studying the actual effects of language is hard (time/effort/budget beyond constraints), so people don't do it.
There is another aspect. Changing languages. Rewriting in a language that is sufficiently different from the original forces you to look at the problem with new eyes. You effectively have greater mental coverage of the problem domain.
This is so true. I usually write things three times: the first time to get a feel for the space, the second to solve the problem at hand. This then gives me actual understanding and them I'm ready to really solve the problem, usually with a fraction of the memory requirements and one or more orders of speed gain and less code to boot.
Very rarely do I hit anything near to an optimal solution the first time out of the gate.
Given the awfulness of so many OOP-based frameworks that I encountered in the 90s, I began to seriously consider that OOP wasn't a better paradigm for most things and that instead it was worse, and simply caused people to rewrite code to the point that it overcame the procrustean bed of inheritance and whatever other tools the language of choice was providing.
That's all well and good except for the fact that your standards are impossible to reach. Even if I do write the exact same project with two different languages, there will always be differences in either the skill of the teams or, if the teams are the same, the amount of experience the team has when they tackle the project.
What we can do is compare similar types of projects in different languages. And the things we can say there are pretty significant. For instance, at my last job using Angular we experienced a particular bug in production a couple times. In my current job our frontend is written in Haskell. I don't make definitive statements that often, but in this case I can definitively say that there is a ZERO chance that bug will happen in our codebase. I can say that because the type system guarantees that that class of bug can't possibly happen.
To be clear, our new application is better (faster, scales better, more maintainable), for the most part because of the improved architecture.
As we were going to do the rewrite anyway, we considered more alternatives than just Python. For programs that have to be reliable and maintainable, I prefer a language with a strong static type system. Haskell has that, and it has a few practical benefits over other tools that made it an excellent choice for our use case.
I remember just three things about the book "Show Stopper!: The Breakneck Race to Create Windows NT and the Next Generation at Microsoft" (1994): the death march, that they tested the OS by writing a file over and over (!) and that they thought the graphic part written in the new object-oriented C++ would save them a lot of time (it didn't)
Sounds right. Additionally, they didn't even reimplement what they had, the article gives the impression that they basically gave up on trying to reinvent relational query optimization ("We heavily modified pyDatalog to query Redis as its knowledge base") and focused on just solving the problem at hand.
Wouldn't a complete rewrite of a module usually be a lot easier if the program is procedural?
I think that is one of the big factors stopping that from actually happening with OO code.
A rewrite is a lot harder if you tap into what exists elsewhere in the codebase.
I bet you have a lot more insight into this than me though.
Absolutely! Thanks for standing up for rigor here.
(The actual argument for functional programming is its adoption by elite programmers like Standard Chartered's Strats team, Facebook's anti-spam group, and Jane Street as a whole.)
On the one hand, I have definitely had this experience - I rewrote a library three times, with large gains in performance, readability, reliability, etc, each time (but mostly on the third time, which was from scratch).
That said, isn't it also fair to say that with a better understanding of the requirements and problem, you may determine that a different language / paradigm is a better choice, in the same way you may decide a different class division is better?
What about skill too? Assuming the same programmer(s) worked on the same projects, they would be more skilled when coming to do the second project. Experience.
So what was the result of your research? I am no fan of OOP style, but I believe it has advantages over procedural style, and I also believe that functional style has advantages over OOP style.
I'm just starting with Haskell and PureScript. So far I'm liking the latter better. It solves a few of their gripes with respect to strings, laziness and records, plus has a more granular/extendable effects system and cleans up the standard typeclass hierarchy. Also `head []` doesn't crash.
Of course Haskell is more mature, has support for multithreading and STM, compiles to native, so it's more performant. But PureScript integrates with JS libraries and seems "fast enough" in many cases. I think it's more interesting as a project too: the lack of runtime and laziness means the compiler code is orders of magnitude simpler than Haskell's, so I could see a larger community building around it if it catches on.
Given that they were on Python earlier, I wonder if PureScript would have been a better choice.
I think PureScript should catch on. The runtime performance story is much more predictable than Haskell, it integrates trivially with the most valuable target platform: JS, it has small output, fixes the warts of Haskell and yet is still pure.
Aside from apps at work, I made some simple physics demos with it http://chrisdone.com/toys/ Perfomance seems good.
> It solves a few of their gripes with respect to strings, laziness and records, plus has a more granular/extendable effects system and cleans up the standard typeclass hierarchy. Also `head []` doesn't crash.
Check out ClassyPrelude[1]. It's a (n opinionated) alternate Prelude that wraps many things up into much more "modern" interfaces. `head` has been replaced with `headMay` (which, as you can figure, returns a `Maybe a`). Most functions can now handle `Text` fairly seamlessly. For an application developer, it's fantastic.
> I wonder if PureScript would have been a better choice.
I have an aversion (based for a large part on prejudice) of things that involve Javascript and its ecosystem :)
I hear many good things about Purescript’s effect system, but I haven’t studied it in detail. This is definitely one of the areas where there is room for improvement in Haskell.
Regarding the type class hierarchy and head being partial, those weren’t really an issue in practice.
A while ago I wanted a better JS for a project, so I tried PureScript and liked it, I have a little experience with Haskell and it was easy to understand and more consistent, however when I tried to do UI components I chose halogen and damn it was too complicated, ended going back to ES6 and React.
The comparison between Stack and Python build tools is striking:
> No messing around with virtualenvs and requirement files. Everybody builds with the same dependency versions. No more “works on my machine” and “did you install the latest requirements?”.
I wonder why the Python ecosystem, which is much more mature, doesn't provide a build tool as delightful as Stack (which is less than 2 years old).
Stack requires package sets (aka "snapshots"), which some kind of CI system (Stackage: http://stackage.org/) has to do a daily build job to see if they all build and pass tests together. That requires some money to keep running, and buy-in from package authors as there is a maintenance overhead each release. It took a few years for Stackage to get enough packages in it to be generally useful, and then we wrote the Stack tool which was able to default to using Stackage snapshots.
There was (and still is a little bit) of resistance to the whole idea of Stackage from the community; people liked the idea of build plans magically being figured out on demand, it's an interesting research problem (it can be hard to let go of an interesting problem when a solution side-steps it all together). I believe eventually many people changed their minds after experiencing the simplicity of using Stack and not having build hell be a substantial part of their development cycle.
Python would likely have to go through the same process. Although with Stack and Yarn providing frozen builds (and QuickLisp); the idea has some precedence, which makes it an easier idea to sell. I mean, Debian and a bunch of other OSes do it like this, but experience shows programmers don't pay attention to that.
Probably for the same reason I greatly prefer cabal to stack. Stack assumes it knows better than me. Cabal just does what I tell it to do. As a domain expert, I greatly prefer the latter. It does what I want, nothing more, nothing less. Stack is a mysterious "solution" to a problem I don't have that works by doing everything differently than I do.
Stack was created because not everyone is a domain expert. A lot of people don't want to be domain experts. They just want something that works without having to know all the details. It was only able (in the business sense) to be created because so many people look at Haskell skeptically anyway, and take any excuse to back away from it. The people behind the development of stack also run a major advocacy initiative trying to get people to use Haskell, so they found it to be an important thing to build.
You don't need to try to get people to use Python. It's already broadly accepted. When people run into trouble, they just say it's the price of using Python, and aren't willing to make the exchange of giving up power to get rid of a minor inconvenience. So there's no business incentive in the Python ecosystem for making the tradeoffs stack does in the Haskell ecosystem.
The whole "Do you have the dependencies and a Python env installed? Noß Then you can't run this script/program." was one of the main reasons I switched from Python to Rust, where cargo as the (very good) package manager comes with the language and, because Rust is a compiled language, you build all the dependencies into your executable you aren't dependent(heh.) on the user having installed a runtime that maybe or maybe not has all the dependencies at the required versions.
I wonder why the Python ecosystem, which is much more mature
I hope I'm not being too pedantic but Python's ecosystem is much larger than Haskell's, it isn't really more mature. Haskell and Python are very similar in age as languages go.
I think newer often tends to easier because it has the benefit of hindsight in this case. Also the old tools tend to get more complicated as time goes on.
"It is said that Haskell programmers are a rare species, but actually the majority of developers at Channable had used Haskell before."
Could you imagine if this wasn't the case? The hurdle to actually get people excited about a language such as Haskell especially moving from something like Python would potentially be huge. Kudos for already having that problem solved.
We're based in Utrect, where Haskell is part of the mandatory curriculum at and the language of choice for many master courses. Because of this, almost all our developers are somewhat familiar with it, or have at least had one course in it in the past, which really helps a lot!
At one company I experimentally wrote OCaml and named the resulting native binaries whatever.py. None ever looked at them. So there is alot of scope for shenanigans.
While it's an interesting look at a change you introduced, that blog title might not come across quite as intended.
If you're having to "secretly introduce" tech, and "get away with it", that suggests there are unnecessary and unproductive constraints on your work; maybe even suggesting that you'd get in trouble for actually daring to make things better.
The "secretly" part refers to part of the story where we had 1 hour to build up quick prototype to pitch to our boss. The title is a bit tongue-in-cheek. It's not that we built this thing in secret for months and then just deployed it. That's also not what the article says :)
We had been planning on replacing Scheduler for a while now, and had already written down some mumblings about what the new design should look like. We were also already discussing whether we would switch away from python back then.
I think the exact opposite of what you are saying is true. We got the freedom to experiment with something new, and to actually make things better along the way.
Not the author, but I think that is exactly what they wanted to convey in the title. The implication is that they're fighting the man and won.
There's a tradition of programmers laying claim to subversively Making Things Better in spite of the bean counters. Sometimes, it is even true, as far as it goes.
It's kind of funny that build reproducibility (which was a major issue before stack) is one of the strong point.
I wonder if, for your project, using cloudhaskell would have been more appropriate.
I have a feeling some of the problems you found could have been solved with that.
You can deploy Python code as a static binary that includes the interpreter along with all dependencies. I heavily use this in production and life is great - deployment means copying one single binary, reverting means running an older one instead. No external dependencies, no pip upgrades, just libc.
> No messing around with virtualenvs and requirement files. Everybody builds with the same dependency versions. No more “works on my machine” and “did you install the latest requirements?”.
While this is nice, of course, I'm not sure that is outcome is unique to Haskell/Stack. It seems like you could accomplish a similar level of reproducibility by building a Docker image or bundling dependencies in some other way.
We are actually using Docker for generating the virtualenv that we ship and running tests now. The motivation for doing this is being able to control the environment; we can run tests and build a package on CI, and we can build the same package locally when CI is down. We don’t use Docker in production.
It is not clear to me how Docker solves the issue of pinning dependencies; I would rather have a file that states the exact version of every package to install, than an opaque blessed container image that has some versions installed, and I do want to have the versions used under source control. Generating the image would not be reproducible (in the sense of having the same Python files inside it) without pinning versions somewhere anyway, right? Or am I missing something obvious?
My understanding is that Docker only stays reproducible if after every change you kill the container and start a new one. Otherwise a particular change may only be working because of a side-effect of a change you introduced earlier and then deleted.
This isn't a huge issue, but still it's nice in declarative systems like Stack and NixOS not to have to worry about that kind of thing.
Thanks for the write up! In the beginning you mention that you ran into some bugs in the Python version that would have been caught by the Haskell type checker. Can you go into more detail about what those bugs were?
"Our lead developer Robert usually comes in a bit later, so we had about an hour to build a working prototype" - why did you only have an hour? What would have happened if the working prototype was not done when he came in?
Instead of using separate monad transformers, we use a single "World" that knows how to provide Redis, logging, iOS, and other typeclass instances.
There is a RealWorld that runs on top of IO and a FakeWorld that runs on top of pure State for unit testing.
This means that we have to wrap every single API into our own "SupportsRedis" and similar APIs, but in the end I think it's worth it! Unit tests are super fast and not intermittent at all.
I tried spacemacs once but I found it too magic. I decided I should learn proper emacs instead of running a random playbox of plugins ontop of plugin. But haven't had the time to properly learn emacs yet.
I have tried various haskell plugins for vim in the past, but they always tended to break so I gave up fixing my config and threw them all away.
Now it's just plain vim (with some non-haskell related plugins) Next to it I have a terminal that reruns tests when a file changes : `stack test --file-watch` . It's simple but it always works.
I'm not sure if the vim stuff got any better lately, I haven't checked. So if you have any suggestions, please tell :)
Always when I see haskell demonstrations eveyrthing looks like just interface declarations.
You can do beautiful interfaces with eg. java also.
But where is the meat where anything actually happens? I rarely see that in these posts.
Yes I could look up the source but I don't have time to read through it randomly.
This looks just so nice and stuff just magically works?:
runWorkerLoop
:: (MonadBackingStore m, MonadLogger m, MonadIO m)
=> WorkerState
-> m WorkerState
And monads to boot! (are monads haskells equivalent of java factories? I kid, I kid :)
The runWorkerLoop function logs a few lines and sends out an initial job request (by enqueueing an event in Redis). It then calls the nested function `go`, which dequeues one event of a TBQueue (a thread-safe bounded queue), matches on the event, and calls the right function to handle it. If the event was not a "stop" event, `go` calls itself to do the next iteration of the loop. `go` takes a WorkerState as argument, which is how it keeps track of which jobs are running, and whether there is an unanswered job request.
In reality the signature is a bit uglier, I simplified it for the post because the point was about effects. In particular we also pass in the configuration, Redis connection details, and a callback to manipulate the TBQueue.
> The issue here is that we cannot run runWorkerLoop and runFetchLoop with forkIO, because we don’t have the right transformer stack.
Am I understanding correctly that this is because, while you can lift e.g. runFetchLoop to something of type IO m (), it's not possible to convert use forkIO on it since it requires an input of type IO ()? Isn't that just a consequence of the fact that Haskell has no possible way of knowing if your side effects can be contained in the IO monad?
It's not about side effects, it's about bookkeeping. When you have a type that indicates that you can do IO, but you're also carrying around bookkeeping data implicitly for things like configurations and data sources, forkIO represents a hard problem.
If the implicit configuration is updated, there's no way to communicate that across threads. The same is true with all the other things monadic layering can provide. How do you call a continuation that points to a different thread? That doesn't even make sense.
So.. Why lie in your type and pretend that those things all make sense? Why not make the type explicit about what makes sense and what doesn't? That way, when someone wants to do something that has no a priori way of making sense, they're required to define how to handle it, such that it makes sense in their specific use case. And that's what the post says they did.
All in all, it's things working as designed. Places where you need to stop and think are set up such that you need to stop and think to use them, instead of barging ahead unaware of the issues.
At the shallowest level, we can't pass `m ()` to forkIO unless m ~ IO, 'cause the types don't match.
But beyond that, there is the question of how that extra context would be passed through. For something like ReaderT this is straightforward. But consider StateT - `set` in one thread can't be visible in the other.
Shouldn't be hard.. Haskell to me so far feels like an ecosystem with way fewer jobs / freelance gigs than there are eager-to-go-commercial enthusiasts hacking away in their spare time..
> but if we could get it done, there would be no going back
The naïveté in this simple statement is so cute.
The list of concerns is also pretty naïve. The main problem you are going to encounter with this project is hiring. If you want to grow this project or if the main developers leave the company, I bet it will get rewritten in a different language in no time.
If the URL to a private repo is not secure, then a whole bunch of people (including GitHub) have a big problem, and exposing jobmachine is the least of their worries ;-)
Actually if you wanted a statically typed compiled functional language of Haskell while keeping the declarative logic paradigm of Prolog, then the Mercury programming language was made exactly for you!
Haskell is a bad language, in my opinion, because you can't tell what the O(n) run-time is for any operation. Instead you just have to "trust" that it'll be fast enough.
Completely untrue. I'm not a Haskell evangelist (I appreciate it for what it is) but I thought I would at the very least point out that most of the documentation for basic data structures (i.e. Data.List[1]) not only are well-documented but have a link on the far-right side of the documentation site that directly shows you the source code and it's usually easy to tell what it's doing. Any developer should be able to grok that code and determine the run-time complexity.
The complexity of many Haskell collection APIs is actually documented unlike with many other languages. These complexities are not changed by the runtime. Only constant factors and memory use are affected by optimisations and this is no different to any other high-level language that actually optimises code.
As a huge Haskell proponent: this is a totally legitimate question, sorry you're being downvoted.
Writing extremely performant Haskell is a very specialized skill. Happily, Haskell is still extremely fast even without fine optimizations.
It depends on what you want to do: if you're writing a moon lander and don't know anything about GHC internals you may be overreaching yourself=) But for most things like web apps etc. knowing the basics is enough.
Good question! None of the existing options that we investigated supported all of our requirements. In particular, all the arrows that can exist in the dependency graph are known ahead of time, but the nodes are not. This means that a job can depend on a job that does not exist yet. (A user can add extra feeds to download, and the merge job should wait for them, even if it had been submitted already.) Furthermore we have a few specific constraints such as “per project, only one of job type x or y may be running at the same time”.
mybrid|9 years ago
dwc|9 years ago
Some time back, someone here on HN posted a comment about rewriting a Java app in... Java. Same basic story of large savings, without changing language at all.
Studying the actual effects of language is hard (time/effort/budget beyond constraints), so people don't do it.
DigitalJack|9 years ago
jacquesm|9 years ago
Very rarely do I hit anything near to an optimal solution the first time out of the gate.
kabdib|9 years ago
mightybyte|9 years ago
What we can do is compare similar types of projects in different languages. And the things we can say there are pretty significant. For instance, at my last job using Angular we experienced a particular bug in production a couple times. In my current job our frontend is written in Haskell. I don't make definitive statements that often, but in this case I can definitively say that there is a ZERO chance that bug will happen in our codebase. I can say that because the type system guarantees that that class of bug can't possibly happen.
Ruud-v-A|9 years ago
As we were going to do the rewrite anyway, we considered more alternatives than just Python. For programs that have to be reliable and maintainable, I prefer a language with a strong static type system. Haskell has that, and it has a few practical benefits over other tools that made it an excellent choice for our use case.
lazyant|9 years ago
cronjobber|9 years ago
NegatioN|9 years ago
I think that is one of the big factors stopping that from actually happening with OO code. A rewrite is a lot harder if you tap into what exists elsewhere in the codebase.
I bet you have a lot more insight into this than me though.
seagreen|9 years ago
(The actual argument for functional programming is its adoption by elite programmers like Standard Chartered's Strats team, Facebook's anti-spam group, and Jane Street as a whole.)
RangerScience|9 years ago
That said, isn't it also fair to say that with a better understanding of the requirements and problem, you may determine that a different language / paradigm is a better choice, in the same way you may decide a different class division is better?
jwdunne|9 years ago
js8|9 years ago
dsacco|9 years ago
pklausler|9 years ago
daxfohl|9 years ago
Of course Haskell is more mature, has support for multithreading and STM, compiles to native, so it's more performant. But PureScript integrates with JS libraries and seems "fast enough" in many cases. I think it's more interesting as a project too: the lack of runtime and laziness means the compiler code is orders of magnitude simpler than Haskell's, so I could see a larger community building around it if it catches on.
Given that they were on Python earlier, I wonder if PureScript would have been a better choice.
chrisdone|9 years ago
Aside from apps at work, I made some simple physics demos with it http://chrisdone.com/toys/ Perfomance seems good.
Karrot_Kream|9 years ago
Check out ClassyPrelude[1]. It's a (n opinionated) alternate Prelude that wraps many things up into much more "modern" interfaces. `head` has been replaced with `headMay` (which, as you can figure, returns a `Maybe a`). Most functions can now handle `Text` fairly seamlessly. For an application developer, it's fantastic.
[1]: https://hackage.haskell.org/package/classy-prelude
chowells|9 years ago
Tell me, have you ever used foldr in Purescript? It just doesn't lead to reusable logic there, so I have no idea why you would.
But in Haskell, foldr is used everywhere. Laziness means that logic built with it is actually reusable.
Ruud-v-A|9 years ago
I have an aversion (based for a large part on prejudice) of things that involve Javascript and its ecosystem :)
I hear many good things about Purescript’s effect system, but I haven’t studied it in detail. This is definitely one of the areas where there is room for improvement in Haskell.
Regarding the type class hierarchy and head being partial, those weren’t really an issue in practice.
Apaec|9 years ago
sid-kap|9 years ago
> No messing around with virtualenvs and requirement files. Everybody builds with the same dependency versions. No more “works on my machine” and “did you install the latest requirements?”.
I wonder why the Python ecosystem, which is much more mature, doesn't provide a build tool as delightful as Stack (which is less than 2 years old).
chrisdone|9 years ago
There was (and still is a little bit) of resistance to the whole idea of Stackage from the community; people liked the idea of build plans magically being figured out on demand, it's an interesting research problem (it can be hard to let go of an interesting problem when a solution side-steps it all together). I believe eventually many people changed their minds after experiencing the simplicity of using Stack and not having build hell be a substantial part of their development cycle.
Python would likely have to go through the same process. Although with Stack and Yarn providing frozen builds (and QuickLisp); the idea has some precedence, which makes it an easier idea to sell. I mean, Debian and a bunch of other OSes do it like this, but experience shows programmers don't pay attention to that.
chowells|9 years ago
Stack was created because not everyone is a domain expert. A lot of people don't want to be domain experts. They just want something that works without having to know all the details. It was only able (in the business sense) to be created because so many people look at Haskell skeptically anyway, and take any excuse to back away from it. The people behind the development of stack also run a major advocacy initiative trying to get people to use Haskell, so they found it to be an important thing to build.
You don't need to try to get people to use Python. It's already broadly accepted. When people run into trouble, they just say it's the price of using Python, and aren't willing to make the exchange of giving up power to get rid of a minor inconvenience. So there's no business incentive in the Python ecosystem for making the tradeoffs stack does in the Haskell ecosystem.
Lev1a|9 years ago
chongli|9 years ago
I hope I'm not being too pedantic but Python's ecosystem is much larger than Haskell's, it isn't really more mature. Haskell and Python are very similar in age as languages go.
quantumhobbit|9 years ago
slezakattack|9 years ago
Could you imagine if this wasn't the case? The hurdle to actually get people excited about a language such as Haskell especially moving from something like Python would potentially be huge. Kudos for already having that problem solved.
arianvanp|9 years ago
nanxor|9 years ago
A course on functional+logic programming is often placed in the 2nd or 3rd year of a typical European 3-3½ year CS degree.
gaius|9 years ago
Twirrim|9 years ago
If you're having to "secretly introduce" tech, and "get away with it", that suggests there are unnecessary and unproductive constraints on your work; maybe even suggesting that you'd get in trouble for actually daring to make things better.
arianvanp|9 years ago
We had been planning on replacing Scheduler for a while now, and had already written down some mumblings about what the new design should look like. We were also already discussing whether we would switch away from python back then.
I think the exact opposite of what you are saying is true. We got the freedom to experiment with something new, and to actually make things better along the way.
_jal|9 years ago
There's a tradition of programmers laying claim to subversively Making Things Better in spite of the bean counters. Sometimes, it is even true, as far as it goes.
framp|9 years ago
It's kind of funny that build reproducibility (which was a major issue before stack) is one of the strong point.
I wonder if, for your project, using cloudhaskell would have been more appropriate. I have a feeling some of the problems you found could have been solved with that.
lima|9 years ago
https://github.com/pyinstaller/pyinstaller
techman9|9 years ago
While this is nice, of course, I'm not sure that is outcome is unique to Haskell/Stack. It seems like you could accomplish a similar level of reproducibility by building a Docker image or bundling dependencies in some other way.
Ruud-v-A|9 years ago
It is not clear to me how Docker solves the issue of pinning dependencies; I would rather have a file that states the exact version of every package to install, than an opaque blessed container image that has some versions installed, and I do want to have the versions used under source control. Generating the image would not be reproducible (in the sense of having the same Python files inside it) without pinning versions somewhere anyway, right? Or am I missing something obvious?
seagreen|9 years ago
This isn't a huge issue, but still it's nice in declarative systems like Stack and NixOS not to have to worry about that kind of thing.
arianvanp|9 years ago
runeks|9 years ago
> * We use all of the five different string types. It is annoying, but it is not a major problem.
cs[1] and the OverloadedStrings extension is all you need, in my experience.
[1] https://www.stackage.org/haddock/lts-8.3/string-conversions-...
fajpunk|9 years ago
BuuQu9hu|9 years ago
TinyBig|9 years ago
arunix|9 years ago
jwatte|9 years ago
There is a RealWorld that runs on top of IO and a FakeWorld that runs on top of pure State for unit testing.
This means that we have to wrap every single API into our own "SupportsRedis" and similar APIs, but in the end I think it's worth it! Unit tests are super fast and not intermittent at all.
yawaramin|9 years ago
arianvanp|9 years ago
I have tried various haskell plugins for vim in the past, but they always tended to break so I gave up fixing my config and threw them all away.
Now it's just plain vim (with some non-haskell related plugins) Next to it I have a terminal that reruns tests when a file changes : `stack test --file-watch` . It's simple but it always works.
I'm not sure if the vim stuff got any better lately, I haven't checked. So if you have any suggestions, please tell :)
javajosh|9 years ago
kisstheblade|9 years ago
You can do beautiful interfaces with eg. java also. But where is the meat where anything actually happens? I rarely see that in these posts. Yes I could look up the source but I don't have time to read through it randomly.
This looks just so nice and stuff just magically works?:
runWorkerLoop :: (MonadBackingStore m, MonadLogger m, MonadIO m) => WorkerState -> m WorkerState
And monads to boot! (are monads haskells equivalent of java factories? I kid, I kid :)
Ruud-v-A|9 years ago
In reality the signature is a bit uglier, I simplified it for the post because the point was about effects. In particular we also pass in the configuration, Redis connection details, and a callback to manipulate the TBQueue.
contravariant|9 years ago
Am I understanding correctly that this is because, while you can lift e.g. runFetchLoop to something of type IO m (), it's not possible to convert use forkIO on it since it requires an input of type IO ()? Isn't that just a consequence of the fact that Haskell has no possible way of knowing if your side effects can be contained in the IO monad?
chowells|9 years ago
If the implicit configuration is updated, there's no way to communicate that across threads. The same is true with all the other things monadic layering can provide. How do you call a continuation that points to a different thread? That doesn't even make sense.
So.. Why lie in your type and pretend that those things all make sense? Why not make the type explicit about what makes sense and what doesn't? That way, when someone wants to do something that has no a priori way of making sense, they're required to define how to handle it, such that it makes sense in their specific use case. And that's what the post says they did.
All in all, it's things working as designed. Places where you need to stop and think are set up such that you need to stop and think to use them, instead of barging ahead unaware of the issues.
dllthomas|9 years ago
At the shallowest level, we can't pass `m ()` to forkIO unless m ~ IO, 'cause the types don't match.
But beyond that, there is the question of how that extra context would be passed through. For something like ReaderT this is straightforward. But consider StateT - `set` in one thread can't be visible in the other.
davedx|9 years ago
dualogy|9 years ago
pka|9 years ago
sjakobi|9 years ago
osi|9 years ago
hota_mazi|9 years ago
The naïveté in this simple statement is so cute.
The list of concerns is also pretty naïve. The main problem you are going to encounter with this project is hiring. If you want to grow this project or if the main developers leave the company, I bet it will get rewritten in a different language in no time.
sjakobi|9 years ago
I also encourage you to find _any_ experience report that tells of difficulties finding the right candidates for a Haskell job.
guptaneil|9 years ago
yawaramin|9 years ago
rkrzr|9 years ago
The point of the code snippet was simply to highlight how nice the Haskell build tools are compared to Python's.
mehaveaccount|9 years ago
unknown|9 years ago
[deleted]
xyzzy4|9 years ago
More on this: https://www.reddit.com/r/haskell/comments/1f48dc/what_does_t...
All of the answers seem insufficient. Basically you can't estimate Haskell run-time unless you are very familiar with the internal Haskell engine.
slezakattack|9 years ago
[1] https://hackage.haskell.org/package/base-4.9.1.0/docs/Data-L...
willtim|9 years ago
seagreen|9 years ago
Writing extremely performant Haskell is a very specialized skill. Happily, Haskell is still extremely fast even without fine optimizations.
It depends on what you want to do: if you're writing a moon lander and don't know anything about GHC internals you may be overreaching yourself=) But for most things like web apps etc. knowing the basics is enough.
ctlaltdefeat|9 years ago
Why did you choose to write your own, regardless of the language?
Ruud-v-A|9 years ago
vorotato|9 years ago
bykovich|9 years ago
[deleted]
eternalban|9 years ago
I'm guessing he is a Python developer and likely he is no longer the lead.
rkrzr|9 years ago
bbcbasic|9 years ago