6 ms·
Kind of all of the above, but I started to realize that I was writing code in a very imperative fashion, since, although I do understand monads and how they kee
by CoffeeDregs 13y ago
Kind of all of the above, but I started to realize that I was writing code in a very imperative fashion, since, although I do understand monads and how they keep IO pure, I felt weird writing very imperative feeling code. e.g. pseudo:
do
f <- openFile 'somefile.txt'
r <- read f
s <- doSomethingToR r
Kinda looked like every other language. Except no one else spoke it and the libraries (at the time) was of highly varying quality..
Also, while I was comfortable with monads, I never got comfortable with monad transformers. I had one monad that was a stack of something like 4-5 monad transformers and I started to feel as though I was losing touch with the beauty of Haskell.
- dchichkov 13y agoHow about Python? You can write IO in a relatively functional fashion in Python: print sum(float(line) for line in open('somefile.txt'))
- CoffeeDregs 13y agoAgreed. Python is my language of choice... ;) Though I'm really starting to look for a statically-typed, compiled language...
- dchichkov 13y agoI'm curious, what for? Performance, type safety or compile errors? If type safety, then in my opinion it is overrated. A side effect of using dynamically-typed language is that developers keep their naming conventions consistent and in check. Because that's the only sane way to avoid stupid typos in a language that doesn't have a compiler. It is not so in the compiled language world. What I often see in the code, where type safety is enforced, - is that developers get sloppy with names! And as a result, there is a significant increase in bugs caused by logic errors. sad
- CoffeeDregs 13y agoPerformance, type safety or compile errors? Yes, yes and yes. A side effect of using dynamically-typed language is that developers keep their naming conventions consistent and in check. I've not found this to be the case. I just discussed method naming in Javascript with a developer today while I was reviewing his code. He's a very good developer and this is an A+ codebase (no, it's not a pile of jQuery plugins...). But he hadn't really thought about how to name some methods and didn't realize the confusion that would be caused in 6-18 months. We left it as he had written it because it would have been a pain to hunt down the dependencies. Were we working in a compiled world, we would have refactored and the compiler would have caught any missed dependencies in a second. What I often see in the code, where type safety is enforced, - is that developers get sloppy with names! I've definitely not seen that. I maintain the same rigor w.r.t. hygiene whether I'm working in statically or dynamically typed languages, but I really miss the compiler when I'm working in dynamic languages. At the risk of sounding really rude, can I ask whether your anecdotes are informed by work with competent developers?
- dchichkov 13y agoWe left it as he had written it because it would have been a pain to hunt down the dependencies. Were we working in a compiled world, we would have refactored and the compiler would have caught any missed dependencies in a second. Ideally, unit tests should take compiler role and be able to catch typos and missing dependencies. There is really no excuse for not maintaining unit tests in the dynamic world. Unless it is a research grade code with limited lifetime. As to your question, I have no idea really. I've stopped judging goodness of other developers and myself some years back.
- wereHamster 13y agoBut why basically write a compiler yourself when you can get the one that comes with the language for free?
- dchichkov 13y ago
- lmm 13y agoPython was my favourite language, but after a year of scala I can't go back. Syntax is almost as lightweight as python, sometimes even lighter (_.something rather than lambda x: x.something is a godsend); tuples and case classes mean it's easy to define a new type for things where you'd use a dictionary or object() in python, and the type system is expressive enough that it doesn't get in the way, not to mention the joys of e.g. the typeclass pattern (which allows a level of dynamicity that would be simply impossible to do sanely in python). There's a mature deployment story (because at that stage it's just .jars) and the huge java library ecosystem is available up to a point.
- dmytrish 13y agoThis may be interesting for you: https://github.com/kachayev/fn.py https://github.com/kachayev/fn.py - this library allows to use Scala-style underscore arguments in Python code (and much more).
- swift 13y agoHeh, that's actually slightly shorter than this Haskell version: print =<< sum . map read . lines <$> readFile "somefile.txt" Someone can probably golf this shorter, though. =)
- evincarofautumn 13y agoThis defaults Num, Read, and Show to Integer—I try to avoid defaulting because it’s kind of a language wart. And speaking of golf: same length but one fewer import by killing the fmap. print . sum . map read . lines =<< readFile "somefile.txt"
- tome 13y agoMuch clearer. I slightly prefer the following though: ((print . sum . map read . lines) <=< readFile) "somefile.txt"
- evincarofautumn 13y agoPointfree makes more sense for a definition, I think: sumFileLines = print . sum . map read . lines <=< readFile Less so inline because of the excessive parentheses or ($).
- abecedarius 13y ago
- michaelochurch 13y agoAs I get older, I realize that the functional/imperative debate is far from over. To say that functional code is "more intuitive" is not only off the point but, I would argue, wrong. Here's a reddit post I wrote about it a few months ago: http://www.reddit.com/r/programming/comments/14hhwa/program_imperatively_when_needed_and_functionally/c7d73tl http://www.reddit.com/r/programming/comments/14hhwa/program_... Imperative code is much more intuitive in the small. That's why we lose when we make side-by-side code snippets of small toy programs and call it a case for FP. The 25-line imperative method is often more intuitive than the highly-dense 6-line functional one. The problem is that imperative code composes very poorly.
- vorg 13y ago> The 25-line imperative method is often more intuitive than the highly-dense 6-line functional one. The 25-line functional program will typically include a 6-line imperative one (with all that imperative code in one place if it's Haskell).
- runT1ME 13y ago>Imperative code is much more intuitive in the small. In a single threaded, deterministic environment yes. But when you're talking multithreaded, I'd disagree. if (user != null) user.company = getCompanyByName("google") being a NPE waiting to happen (in a multithreaded environment) is certainly non-intuitive.
- Peaker 13y agoImperative code looks like imperative code. Most Haskell code isn't though. Also, a 5 layer transformer stack is typically wrapped in a newtype, so it looks like an ordinary monad with the operations you need.
- tome 13y agoYes that is indeed unpleasant style. That's why you should write doSomethingToR <=< read <=< openFile instead.