[HN Gopher] Why is learning functional programming so damned har...
___________________________________________________________________
Why is learning functional programming so damned hard? (2019)
Author : allenleein
Score : 119 points
Date : 2021-08-15 14:06 UTC (8 hours ago)
(HTM) web link (cscalfani.medium.com)
(TXT) w3m dump (cscalfani.medium.com)
| _query wrote:
| In my experience when learning functional programming with
| Haskell there are two kinds of complexity:
|
| 1. Complexity caused by the change of paradigm: This specifically
| hits programmers with a lot of experience in OOP languages. For
| getting into the FP-mindset your brain needs a bit of time to get
| rewired. You need to switch thinking about mutating objects to
| thinking in mapping streams of data. Given that many OOP
| languages are adopting functional ideas like map and fold/reduce,
| nowadays a lot of developers already have a bit of experience in
| thinking in the FP-way, and this will get better with time.
|
| 2. Complexity caused by the tools: There's a reason the author in
| the above post started out with Elm instead of Haskell :-)
| Writing a few recursive functions in haskell is still pretty
| simple. Where it get's very complex is when you want to build
| real world applications. To build a simple web app you need to
| 10s of decision on what tools and libraries to use. Here's a
| couple questions you'll need to find an answer to when building a
| haskell app:
|
| - What GHC and what language extensions do I need? How do I
| install it? - What package manager do I use? Cabal, nix, stack? -
| What web server library? - What database library do I need? Do I
| need an ORM, are there even ORMs in haskell even though there are
| no objects? - What HTML template library to use? - How do I
| compose it all together? What is a monad stack?
|
| When you have only very few experience in haskell it's really
| hard to not get stuck here. The quality of documentation of most
| haskell tools also doesn't very much help here.
|
| I believe that the value haskell can bring is signifcant, and by
| fixing the tooling situation we can a lot more people to adopt
| haskell in the future.
|
| With IHP we're trying to fix the tooling situation and build a
| haskell-based web framework that is as easy to use a rails or
| laravel :) To combine the benefits of purely-functional
| programming with the RAD approach of rails, laravel and django.
| It's now already the most active haskell web framework and we
| have many people starting their haskell journey with IHP.
|
| We have live reloading in dev mode, a JSX-inspired template
| language and many code generators to quickly get started with
| shipping real world apps.
|
| Check out this video of building a simple blog app in IHP:
| https://www.youtube.com/watch?v=UbDtS_mUMpI To get started
| (supports macOS, linux, windows) check out the IHP Website:
| https://ihp.digitallyinduced.com/
| soheil wrote:
| Honestly a much less gimmicky and concise guide can be found here
| [0]. The focus is on scala but it does away with longwinded
| storytelling style explanations and petulant comics. It gets to
| the point, gives a couple of examples and tells you exactly why
| each tenant of functional programming is useful in one sentence.
|
| [0] https://nrinaudo.github.io/scala-best-
| practices/definitions/...
| throwaway81523 wrote:
| The saying about Haskell is that it has the steepest unlearning
| curve. It probably helps to have seen some abstract algebra since
| many of its ideas come from there. The online book
| learnyouahaskell.com is pretty readable though.
|
| As that guy was a big executive whose time was interchangeable
| with money, he might have had better luck treating FP as a topic
| in math that he was having trouble with, and hiring someone for
| one-on-one tutoring, either in person or online. It might have
| gotten him through the various stumbling blocks quicker.
| bennysomething wrote:
| Christ that's a long winded article! Also I'm getting tired of "I
| learned to program on a stone tablet with a chisel" type stories.
| Wow, you wrote assembly, swoon!
| agumonkey wrote:
| culture and the paradox of simplicity
|
| fp and math go abstract fast, people can't see any tangible
| machine or pragmatic process
|
| fp-ists enjoyed that and pushed it to 11, making it even weirder
| jacquesm wrote:
| Hot tip: use the stack that you know best if you want to ship.
| Feel free to experiment with other stuff for
| hobby/entertainment/educational purposes.
| default-kramer wrote:
| The author's struggles with Haskell resonate. I suspect it's just
| a very hard language to learn. I've given up attempting to learn
| it at least twice now.
|
| I took Martin Odersky's Scala MOOC sometime around 2012-2014 and
| it was easy. It just made sense and the IDE experience was nice.
| I would recommend it to anyone who uses C# or Java and wants to
| learn FP. Although after 8 years I don't know if it's still as
| good, or if something better has come along. Either way, the
| course is still available: https://www.coursera.org/learn/scala-
| functional-programming
|
| Next I worked through SICP and that was the best CS book I've
| read, although significantly more difficult than the Scala
| course.
| crvdgc wrote:
| Specific to the "jargons" the author talked about. I find recent
| introduction level Haskell books actually do a surprisingly good
| job covering all the concepts the author mentioned. And they
| don't suffer from the online learning material problems.
|
| The two books I read and can recommend are _Programming Haskell_
| by Graham Hutton & _Get programming with Haskell_ by Will Kurt.
|
| Another source that helped me a lot is the video series _Category
| Theory_ by Bartosz Milewski [0]. It requires basically no
| background on category theory and defines all the concepts along
| the way. Bartosz also uses Haskell code as examples. You only
| need to know the syntax up to type class to understand.
|
| As for the awful experience people get from learning Haskell, I
| think it depends a lot on people's expectations.
|
| Most people only learn one language from school or early career,
| and then migrate their experience from one language to another.
| You don't learn the concept of "stack" twice, you only "learn"
| how to express them with a different syntax. So people can
| "learn" new languages with significantly lower effort than they
| learned the first language.
|
| And when they find Haskell or other ML-family functional
| programming languages, they can't find the corresponding concepts
| in their known language. This time people actually need to learn
| new concepts as they learned their first language.
|
| The experience is very similar to learning algorithms or OOP
| design patterns. And I don't think it's harder to learn Haskell
| up to the level mentioned by the author than e.g. reading the
| gang-of-four book.
|
| [0]:
| https://youtube.com/playlist?list=PLbgaMIhjbmEnaH_LTkxLI7FMa...
| lucie_cupcakes wrote:
| Here is an archive of the text-only view from the article:
| https://archive.is/aoB1o
| revskill wrote:
| Why using a StateMonad when i could just use OOP ? Simple,
| elegance and easier to read, write and test.
| jokethrowaway wrote:
| As someone who is huge on Functional Programming, I'm not sure
| you're reaping the benefits you're talking about. Your dedication
| is impressive, but it's nowhere close to being required to build
| any kind of product.
|
| Sure, I agree that learning FP will make you a better
| development, but spending all these learning resources in order
| to build a product is not very convenient.
|
| I've been shipping code with mediocre languages all my life. Even
| now, I routinely pick node.js over Haskell or Rust just because
| the complexity of the solution I need to build is not high enough
| to justify writing amazing bug-free code. Sure, you may get more
| bugs and less help from the compiler, but there is more material
| online and I can easily find a cheap developer to throw at the
| project.
|
| I've been developing for 15 years. After 5 years of C++, PHP, JS,
| I decided to jump into Haskell for my side projects. I can't say
| the learning curve was as hard as you made it out to be: there
| are plenty of great resources for learning Haskell and you don't
| need to go through Elm or Purescript (which weren't even a thing
| when I learnt Haskell). Actually the differences between the
| languages may make things more confusing.
|
| In the last couple of years I stopped using Haskell completely,
| simply because Rust (a language designed to build things, unlike
| Haskell which is more of a language research project) is
| functional enough, pleasant enough to use and is developing a
| nice community. The most useful FP concepts trickled down in
| other languages.
|
| FP already won and nobody even noticed it.
| tel wrote:
| Learning FP takes real investment both in time spent learning and
| practicing the concepts and in time spent slowly misusing them in
| real projects until you develop your taste for where they're
| appropriate. This investment is regularly underestimated.
|
| Using FP introduces real advantage in terms of taste and
| simplicity, meaning that "advanced" concepts are not nearly as
| prevalent as someone who just learned them might hope. The rule
| of 3 is helpful and under-applied. Programmers new to FP get
| eager to use cool tech as opposed to leverage improved taste.
|
| FP can be utilized in many languages but in ones that don't guide
| your hand toward it--your Haskell, your OCaml, your Elm--it's
| easy to have it "mix" with other styles. It is _not_ the case
| that combining FP and non-FP styles immediately make sense or
| work. It _is_ the case that the strengths can be combined if done
| thoughtfully.
|
| All of these points generalize, though. As with any programming
| work, taste is important. It takes a while to develop and often
| needs to be developed within the context of a team. Tasteless FP
| is an awful, awful waste of time, energy, money.
|
| Someone who likes to throw all the jargon at your is a hobbyist,
| a proselytizer, or a fan. Not terrible, but not necessarily
| someone who can yet manage all of the necessary tradeoffs and
| balances. We take that sense of taste somewhat for granted in
| "mainstream" programming styles.
| makerofthings wrote:
| I have a good 30 years of C/C++ under my belt and have been
| learning Haskell for the last 4 years. You can write a buggy
| version of a program in C after spending an afternoon learning
| it. You can write a bug-free version in haskell but you'll be
| spending a few weeks worrying about monads. I think C just looks
| easier because you can learn enough to be dangerous without much
| effort, getting to a level where you can write reasonably safe C
| will take a lot longer than getting to that same level in
| Haskell.
| the_only_law wrote:
| After trying to join in on the monad jokes for forever, I
| opened up the the Wikipedia page on Monads (in the functional
| programming context, not the page in raw category theory) and
| it actually kinda made sense.
| exdsq wrote:
| The problem that made monads make sense for me was when I had
| to chain (err, val) tuples for six or seven functions that
| only took val and handling the (err, _) bit was awkward.
| Someone showed how to rewrite it using monads to handle that
| without the boilerplate and voila.
| javert wrote:
| If someone would make a tutorial that replicates the
| process you just described, that might be a good way to
| teach monads.
| ghayes wrote:
| I strongly suggest starting with a language like Elm to
| get into FP, since you start to use `map` and `andThen`
| quite often, but you also get sick of writing `a |>
| Result.andThen fn1 |> Result.andThen fn2`. This can help
| a programmer realize why it might be better to have a
| concise syntax for this, like: myFun :
| String -> Result String Int myFun a =
| do b <- fn1 a c <- fn2 b
| return c
|
| That said, I think the other problem with Haskell is the
| definition of the bind operator: it is not obvious to a
| beginner which concrete function is actually being called
| for each monadic operation. Idris2, for instance, lets
| you specify the bind operator in its do notation[0].
|
| [0] https://idris2.readthedocs.io/en/latest/tutorial/inte
| rfaces....
| ModernMech wrote:
| I like the way that "Learn You a Haskell" puts it:
| "If we have a fancy value and a function that takes a normal
| value but returns a fancy value, how do we feed that fancy
| value into the function?"
|
| That's basically all a monad is. If you know what map() does
| (in Haskell terms, map is a "functor"), then you know what a
| monad is, as it's just a fancy map().
|
| I'll put it in Rust terms: let x: Option<u8>
| = Some(5); fn foo(x: u8) -> Option<u8> {...}
|
| How do we apply the function foo to x? That's what monads are
| for.
| marcodiego wrote:
| Because you're already used to a very different approach to
| express the solution to a problem. It is like somebody who
| already knows an western language trying to suddenly learn
| Mandarin.
| nowherebeen wrote:
| I equate it to a skier learning to snowboard. A skier points
| their toes downhill to go down the mountain; a snowboarder
| points their toes perpendicular. Once you are used to pointing
| your toes downhill, its very hard for the mind to switch
| context to perpendicular because your mind is telling you
| that's how you stop.
| Jtsummers wrote:
| Hah, I was pondering how to write a longer comment expressing
| this same thing so I'll piggyback on yours.
|
| Paradigms are modes of thinking. You can't just pick up a new
| paradigm on the fly when you've spent your entire life in
| another one. Some individuals are exceptions, but most of us
| aren't so lucky as to have such a natural aptitude for changing
| our minds on the fly.
|
| In order to be introduced to a new paradigm you have a couple
| options:
|
| 1. Sink or swim. In Haskell, this is the monad tutorial. Why
| the hell do people start their instruction here? Did _they_
| start here? If they did, did they _succeed_ from that point or
| did they have to find another path and just forgot that this
| was a really stupid way to start?
|
| 2. Baby steps. "See Spot. See Spot run. Run Spot, run!"
| Learning Italian (previously Spanish), this is literally the
| level I'm at (actually, a bit better, but still highly
| constrained by my limited vocabulary). In Haskell, this is:
| double :: Int -> Int double x = 2 * x quadruple ::
| Int -> Int quadruple x = double (double x)
|
| Simple functions tested in the REPL. Then you teach them about
| function composition (drawing on their knowledge from
| mathematics, where it's the same idea and not merely an
| analogous idea) and make a point-free version of quadruple.
| Then you show how functions can be passed around so that you
| can do: square_function f = f . f
| quadruple = square_function double
|
| Maybe give that first function a better name, my coffee hasn't
| kicked in yet. My point, though, is that functional programming
| in Haskell does _not_ rely on monads when _teaching_ the topic.
| There are a million things to teach before you even reach that
| point, and only once the student has a foundation in Haskell 's
| syntax, base semantics, and type system do they need to be
| introduced to monads. At which point it'll make a lot more
| sense because they'll be able to grok what monads add to the
| language.
|
| By analogy (hah!), we don't start C language learners with
| implementing a generic swap or sort function. That would be way
| beyond their initial capability, relying no too many ideas that
| they have no foundation for (that said, it's a shorter path to
| that in C than monads in Haskell).
|
| So why do people think that learning a totally novel (to them)
| paradigm like functional programming, especially in the uber-FP
| language Haskell, can be done by starting at the deep end
| without studying its fundamentals?
| choeger wrote:
| Because functional programming is so damned hard if you don't
| grasp recursion. Otherwise, it is simple.
|
| Sorry for the cheap pun, but I think the main difficulty is
| getting along with recursion.
|
| And corecursion, of course ;).
| bsaul wrote:
| recursion is always synonymous to me of unbounded memory usage.
| Understanding the memory consumption of a for loop updating a
| local variable looks easy. But a recursive function ? forget
| it...
| emodendroket wrote:
| Well that's why you want a function to be tail recursive,
| right?
| bsaul wrote:
| yeah but how do i know for sure that the compiler is going
| to optimize the memory or not ? Some compilers are smarter
| than other to rewrite recursion in a tail recursive way,
| and others aren't, and it's probably not possible all the
| time anyway..
|
| It seems like a very convoluted way to do a simple thing (
| sometimes).
| carnitine wrote:
| A tail recursive function can always be optimised into
| code which does not consume memory on recursion, and it's
| a pretty basic fact to learn about a given
| language/implementation.
| c-cube wrote:
| Functional languages will typically guarantee you that
| tail recursion is constant space. The exception is
| languages running on a FP adverse runtime such as the
| jvm, and they tend to provide a special keyword and
| rewrite into a loop.
|
| Also, mutual recursion is a bit more general than loops
| :)
| emodendroket wrote:
| In Scala, as I recall, you could annotate a method as
| tail recursive so it wouldn't build if it weren't. A
| serious functional language pretty much has to have an
| answer for this since you're supposed to use recursion
| instead of iteration.
| Twisol wrote:
| I suspect you think about recursion in terms of a call
| stack, yes? So when you have tail recursion, you're still
| pushing a frame onto the stack by default, _unless_ the
| compiler recognizes that it can optimize that way. Yes?
|
| The traditional FP model of computation doesn't have a
| call stack. It proceeds by reduction: replace one
| subexpression with another, in the program text itself,
| and repeat until you can't do it anymore.
|
| So if I've got a fibonacci function in two clauses, `fib
| 0 a b = b` and `fib n a b = fib (n - 1) b (a + b)`, then
| a reduction may look like this: fib 3
| 0 1 -- initial program = fib 2 1 (0 + 1)
| -- substitute second clause of `fib` = fib 2 1 1
| -- evaluate `+` = fib 1 1 (1 + 1) = fib 1
| 1 2 = fib 0 2 (1 + 2) = fib 0 2 3
| = 3 -- substitute first clause of `fib`
|
| Notice how the tail-recursion naturally falls out of the
| substitution steps performed by the interpreter. There
| are no stack frames; the whole "rest of the program"
| (which is what a call stack _is_ ) is just the program
| itself.
|
| This isn't just an analogy; this is the way computation
| works in an FP. To an FP system, the _call stack_ is the
| invisible, behind-the-scenes optimization.
| asimpletune wrote:
| They can be made to work very much the same with the
| compiler. The main difference is tail recursive or not.
| Basically whether the answer is being accumulated along the
| way or requires returns from the call stack to accumulate the
| result.
|
| Otherwise there's no law of computer science making the two
| very different. Some language compilers implement recursion
| naively, that's mostly it.
|
| The call stack itself is literally just a stack provided by
| the OS with restrictions meant to protect the other programs
| in the os.
| jarcane wrote:
| Yes. Fundamentally, the problem is cultural, not
| mathematical. A modern language like Racket with proper
| recursion optimizations will compile and optimize a
| recursive solution that is as fast or nearly (and even
| sometimes faster) than a mutable imperative one.
|
| The problem is that the idea of recursion as slow or
| resource hungry has become a kind of circular just-so story
| among imperative programmers and compiler developers who
| don't want to write recursion optimizations (or don't even
| know how).
|
| The argument goes that recursion is slow, so don't use
| recursion, and if you raise the idea of optimizing
| recursion, the compiler dev dismisses it, because why would
| you write recursion support, recursion is slow.
|
| Now it's fair to say in an earlier era, this was somewhat
| justifiable, but the logic has been passed down far longer
| than it's actually been true of the technology available. I
| remember reading "recursion bad" in C books in the 90s, and
| it's _still_ so pervasive that even though TCO has been in
| the JS standard since ES6 years ago, most browsers still
| can 't be bothered to support it.
| sltkr wrote:
| I think recursion is just one of the hurdles.
|
| Another one is the use of higher-level functions and function
| composition.
|
| Another one is the use of monads (at least in pure functional
| languages like Haskell).
| nightski wrote:
| Monads aren't really related to purity. Haskell uses one
| instance of a monad, the IO monad to encapsulate IO. But
| there are other ways of doing it. Most monads have nothing to
| do with side effects.
|
| You see things like functors/monads all the time even in
| regular imperative languages. For example in .NET we have
| Linq, Nullable types, etc... They aren't as well defined as
| in Haskell but still an incredibly useful pattern.
|
| You also have higher ordered functions and whatnot in
| imperative languages now. In fact, in JavaScript and .NET
| they are used all over the place.
| DaiPlusPlus wrote:
| I don't believe .NET's `System.Nullable<T>` is a monad. For
| example, a type that can encapsulate _any_ other type
| fulfils the definition of a _monadic-value_ , but
| `Nullable<T>` cannot be used with reference-types and
| delegates, only a strict subset of value-types (as
| `Nullable<T>` itself is a value-type, but you cannot use
| `Nullable<T2>` for T1 in `Nullable<T1>`).
|
| While .NET allows for composition with delegates, it's not
| very smart, and results in unnecessary type information
| erasure; for example in Linq if you take a projection of a
| fixed-size list, then that length information is lost if
| you then add another step after the projection. (Linq
| internally has some ugly, but inconsistent implementation
| hacks; for example, IList<T> length information may be
| preserved but IReadOnlyCollection<T> length information
| will not.
| nightski wrote:
| C# has nullable reference types now. But I agree it's not
| perfectly a monad in implementation due to engineering
| decisions. But the pattern generally follows that of the
| Option monad in Haskell, even if it falls short. If you
| know the Option monad you'll find it really easy to pick
| up .NET's nullable types.
|
| That's my point, you find these patterns all over in
| common programming languages and even though they are
| hard to learn it's worth it.
| recursive wrote:
| It's going the other way that's the problem. I understand
| .net nullable, including some of the weird edge cases and
| trivia. None of that seems to provide any illumination
| into the working of more general monads.
| nightski wrote:
| Weird, when I was learning Haskell I felt like the Option
| type looked very familiar. Then when I learned about fmap
| and bind it was immediately obvious why these would be
| useful. You mean I can apply a function to a nullable
| type that has no knolwedge of nullable? Cool! Or I can
| compose general operations on nullables? That is neat.
|
| In fact I think this was the easiest way for me to learn
| monads - to learn them in the context of things I already
| understood.
| DaiPlusPlus wrote:
| That's because Nullable<T> and nullable-reference-types
| _aren 't_ monads - precisely because they aren't
| composable.
|
| I think this SO post covers it well:
| https://stackoverflow.com/questions/44965/what-is-a-monad
| sltkr wrote:
| All essential applications of monads in Haskell are there
| to work around the limitations of purity. The I/O monad, ST
| monad, State monad, etc.
|
| Yes, I know List and Maybe are also technically monads in
| Haskell. But you don't need to think of them as monads or
| even understand monads to do anything useful with them.
| Applying monad operators to lists and maybes is only
| occasionally useful.
|
| In most impure functional languages (LISP, ML) you rarely
| model any data types as monads explicitly. As soon as you
| have side-effects, they lose their appeal.
| nightski wrote:
| This is just not true, you throw out some of the most
| useful monads :)
|
| Also ST and State have no side effects. The only monad in
| Haskell that has side effects is IO (unless you were to
| sneak in an unsafePerformIO but that is an entirely
| different discussion). So they aren't there to work
| around the limitations of purity, because they are pure.
| sltkr wrote:
| > This is just not true, you throw out some of the most
| useful monads :)
|
| Namely?
|
| > Also ST and State have no side effects.
|
| I didn't say they do. I said they are useful only because
| Haskell doesn't allow side-effects. In ML or Lisp you'd
| just update a local variable instead.
| nightski wrote:
| Lists, Option, Either, Reader, Logging (non-effectful),
| STM etc... There is even a probability monad that I have
| found quite useful.
|
| ST & State are far more useful than updating a local
| variable. If you are going to choose the simplest use
| case for them ever and then say that is the only thing
| they can do it is not a productive discussion. The state
| monad is a lot like a context object that allows state to
| flow through function composition (for functions that
| have no knowledge of such state). For example you could
| compose a bunch of functions and have the results of each
| function call stored without changing any of the
| functions to know about the operation. It's a method of
| abstraction and encapsulation.
|
| It's not just monads that are useful either, it is the
| full hierarchy of Monoids, functors, applicatives,
| monads, etc...
| nwallin wrote:
| I disagree entirely.
|
| I understand recursion just fine. I can look at a problem and
| think "this problem space is correctly represented by a
| tree/graph" and can meaningfully translate that into a program
| that shoves the data into a tree/graph-like data structure, and
| my natural inclination when computing on a tree/graph-like data
| structure is to use recursion.
|
| On the other hand, I understand that _not all problems_ lend
| themselves to recursive solutions. I can look at a problem and
| think "this problem space is correctly represented by a
| matrix" and the reality is that linear algebra problems are
| often iterative, not recursive, in nature. It is certainly
| possible to do the simplex algorithm recursively with immutable
| data, but it's just so much straightforward to do it
| iteratively on a mutable matrix.
|
| The other thing is that most of my day job is just hooking one
| API up to another API to achieve my business's desired outcome.
| I don't need "interesting" algorithmic solutions for 95% of
| what I do. I just... extract data from one API and plug the
| data into another. You don't need recursion for that, and the
| "list of steps to do in order and (possibly) loop over that"
| paradigm with whichever seasonings you wish to add to it is
| just fine. (OOP is the flavor of the ~~day~~century at my
| company)
|
| edit: I forgot the bit that ties it all together. I am
| absolutely no good at functional programming. I've tried to sit
| down and learn Haskell or Lisp a dozen times and always failed.
| I've bought books. I'm still no good. It just takes me ten
| times as much code that's completely unreadable to do something
| that would be simple and straightforward in C++.
| onlyrealcuzzo wrote:
| I also think that most people who learn a functional language
| try to take what they know in an imperative language and
| translate it on the fly to a functional paradigm.
|
| This seems like a lot more work than just learning how to think
| functionally.
| TchoBeer wrote:
| Alternatively, learning a new thing is easier if you have a
| grounding somewhere. Maybe the ideal would be a guide like
| "this is how functional programming differe from imperative
| programming"
| dagw wrote:
| The intro to programming course for the math department at my
| University was taught in Haskell. And it was really
| interesting to see how people who had never programmed before
| on the whole did better than those who had a bit of
| programming experience.
|
| Those that had programmed before kept trying to make Haskell
| behave how they thought a programming language 'should'
| behave, while those who had never programmed just looked at
| Haskell and went "I guess this is what programming is" and
| just rolled with it.
|
| The only problem was that once they moved onto the
| intermediate course, taught in Java, they where completely
| lost again.
| scns wrote:
| Introduction to Programming at CMU is done in SML. They
| make the same observations as you. Those that have prior
| exposure to programming struggle. Those students without
| experience find it easy. They are a bit baffled in the next
| course, which is done in an imperative language.
| rgrmrts wrote:
| 15-150 (during my time), but it wasn't the intro to
| programming - the course is titled "introduction to
| functional programming". The intro to programming is
| Python (unless it changed).
|
| The trajectory for students is Python to C to SML (15-110
| to 15-122 to 15-150). Some people take the C and SML
| courses in the same semester.
|
| I was really happy to have been introduced to many
| different paradigms over the course of a few years. But
| to both your points, once we moved on to Java I had a
| really bad time.
| Banana699 wrote:
| > I think the main difficulty is getting along with recursion
|
| meh, recursion is easy. Recursion is mainstream. It _began_ as
| a way to fake a loop without mutation, but I struggle now to
| remember a mainstream language without it.
|
| The hardest part is all the new patterns you have to grok, it's
| like learning programming again from a blank slate, because it
| kinda is. It doesn't get any easier when Haskell decides it
| needs 7 new syntaxes and someone rushes to compose them all in
| one line.
| jghn wrote:
| Most people are taught from day 1 to code in some combo of
| imperative and OOP styles.
|
| The issue is not that FP is hard to learn. The issue is that most
| people start off from a much lower baseline knowledge-wise than
| they will when learning a new imperative and/or OOP language,
| framework, etc.
| moralestapia wrote:
| I was going to comment on a similar line.
|
| I come from the OOP school and have done 10s-100s(?) of C/C++
| projects, which I like, btw. But when I discovered FP it was an
| eye opener, the breadth of things that became
| possible/tractable is great, even my OOP programs became much
| better because of it.
|
| I think that the OOP curriculum is actually a regression, and
| would recommend anyone who is just starting out to try out FP
| first.
| eightysixfour wrote:
| As someone who only dabbles in code, I'm very interested in
| starting FP first, but I find that the beginner tutorials
| mostly assume previous programming knowledge/skills, and the
| communities aren't really geared towards folks who don't have
| backgrounds from other areas.
|
| It is certainly possible I'm not looking in the right place
| for the right thing, but it should probably be an area of
| improvement for those communities in the future IMO.
| Twisol wrote:
| You might like "How to Design Programs": http://htdp.org/
|
| It appears to exclusively work with the usual FP
| understanding of computation as _reduction_ (simplification
| of an expression), avoiding all named mutable state. This
| is (in my opinion) the most important and fundamental
| difference between functional and imperative, and is
| something you miss if you try to learn FP in, say,
| JavaScript.
|
| It also doesn't seem to assume any prior experience with
| programming. The last chapter even has a section
| specifically directed at students who aren't computer
| scientists or software developers.
| blagovest wrote:
| Hey! I am writing an ebook about high-level programming
| concepts that starts off with a FP view point and builds on
| top of it. If that sounds interesting, I'd love to share (I
| am eventually going to sell it but I am fine giving away
| drafts)
| eightysixfour wrote:
| Absolutely, would love to take a look.
| donglover69 wrote:
| Exactly. I came from a math background and only ever used
| Wolfram Mathematica for programming, and naturally used
| functional programming. Later on I tried to learn imperative
| programming and it boggled my mind. The idea of changing a
| state over and over seemed so janky to me.
| CalChris wrote:
| Some people, when confronted with a problem, think "I know, I'll
| use regular expressions." Now they have two problems.
|
| That isn't even a criticism of regular expressions nor is this a
| criticism of functional programming. It's more about that
| fashionista need to use something rather than solve something.
| dtagames wrote:
| I had a chance to speak with John Backus when I worked at IBM
| where he invented functional programming with the goal of
| removing some of the spaghetti and incomprehensibility of
| imperative and procedural code. It certainly was _not_ an
| immediate hit!
|
| Despite being an IBM Fellow (the company's highest rank with
| complete freedom to work on whatever you want), John was having
| trouble getting any traction for his ideas. I certainly didn't
| grok it at the time. I couldn't see the utility over the
| procedural PL/AS and imperative assembler we were already using
| to create the mainframe's higher-level language compilers.
|
| I've since become a big believer in the functional style, sadly
| after John's passing. It's certainly not the solution for
| everything. Even the lambda calculus requires that you feed it a
| starting series of "magical" integers to work. But functional
| _is_ a useful way of thinking about programming, especially for
| library functions.
|
| I would say the key difference between the functional style and
| imperative/procedural is not the presence of recursion but the
| lack of _state_. A functional function cannot have any internal
| state store, nor rely on anyone else having one. In other words,
| all of its arguments and values must be fully defined by
| parameters. This is a super-critical concept in debugging because
| it helps bulletproof your function.
|
| Having said that, no real working program can be fully
| bulletproofed with the functional style because we need to hold
| onto state in real programs. (Is the user logged in?, etc.) We
| cannot pass these values in every single time and have a
| practical program.
|
| I think merging these concepts of functional when you can and
| state when you must is the easiest approach. Certainly there are
| many functions in every program which are functional in style in
| that they do not contain or rely on any state, and those are good
| jumping-off points for starting to understand the functional
| style.
| emodendroket wrote:
| Of course a program without side effects is useless, but the
| idea is deferring those as much as possible, isn't it?
| carnitine wrote:
| No, a program without effects is useless. Side effects, i.e.
| some action done _on the side_ while evaluating the program
| are not required. There are other ways to treat effects in
| programs, particularly as values.
| emodendroket wrote:
| Unless you display them, save them, send them somewhere,
| etc, they're useless. Therefore, a program without side
| effects is useless.
| carnitine wrote:
| Effects, yes. Side effects are a particular form of
| effect. A pure functional language can compose an
| effectful value that is interpreted by a runtime, but no
| effect happens on the side as the program is evaluated.
| emodendroket wrote:
| That's not really what side effects mean in programming:
| https://en.wikipedia.org/wiki/Side_effect_(computer_scien
| ce)
|
| > In computer science, an operation, function or
| expression is said to have a side effect if it modifies
| some state variable value(s) outside its local
| environment, that is to say has an observable effect
| besides returning a value (the intended effect) to the
| invoker of the operation.
| ratww wrote:
| GP is correct. There are _zero_ side-effects _inside_ a
| pure program. All the side-effects happen outside it, in
| a "runtime" (a better name IMO is "imperative shell")
| that exists totally separate from the program. The main()
| function of a pure program executes completely and
| terminates before any side effect has a chance to happen.
|
| I put quotes around runtime because it's not a runtime
| like an interpreter in dynamic languages, or a library
| that you can call from inside your pure program. This
| runtime just calls your _main()_ function, which return a
| complex value (it 's a chain of lambdas, to spoil it)
| that is interpreted by this runtime or "imperative
| shell".
|
| I understand this sounds unintuitive and might seem very
| confusing, but this is what makes useful pure programs
| possible. These couple presentations show how this type
| of boundary between imperative and functional code works
| with simpler type of program [1]. The only difference is
| that Haskell's "imperative shell" is lower-level than the
| presenter's. It only deals with IO, etc, whereas the
| presenter's imperative shell also has some domain code.
|
| [1] https://www.destroyallsoftware.com/talks/boundaries /
| https://www.destroyallsoftware.com/screencasts/catalog/fu
| nct...
| dtagames wrote:
| Yes! JS and TS allow this kind of functional style which I
| try to adhere to. There must be state, of course, but as few
| functions as possible should rely on it and certainly _no_
| function should "reach" into anywhere else to get a value.
| Those things have to be passed-in.
|
| The change from AngularJS to Lit (or React), is an example of
| this kind of functional refactoring. AngularJS had two-way
| databinding (state!) and it attempted to pass that state
| upward when things changed. This made horrible spaghetti and
| impractical large apps.
|
| Lit and React are only top-down. Yes, each component has
| state but only at the top. It gets passed-in as a parameter
| to other things, but they can't change it in return. This is
| much more modular and debuggable.
| neolefty wrote:
| Yup, React is all functional these days, and pretty
| widespread. My team, for example, is "discovering" the
| benefits of functional approaches, and it's nice that it's
| a gentle slope.
| recursive wrote:
| Use of state is still widespread. `useState` is a
| function in the javascript-specification sense, but not
| in the FP sense, since its only purpose is a side effect,
| not the return value. I don't think react can do anything
| useful if you use only FP constructs.
| ratww wrote:
| It would be possible have a purely functional React if 1)
| the current state of the component were injected via an
| argument, and 2) instead of a _setState_ call we just
| returned the state changes we needed.
|
| With that our code would be 100% pure, and all the side-
| effect part would live outside our JSX files, similar to
| how Haskell does.
| emodendroket wrote:
| The biggest downside with doing it in something like JS is
| you don't have the same under-the-hood optimizations. In
| functional languages it's not actually going to allocate a
| whole new array each time an immutable list is appended to,
| but that's exactly what will happen in JavaScript. But yes
| I agree, these concepts are showing up everywhere, even if
| you don't do "FP."
| pyrale wrote:
| > In functional languages it's not actually going to
| allocate a whole new array each time an immutable list is
| appended to, but that's exactly what will happen in
| JavaScript.
|
| Efficiency depends on how your js runtime is optimized.
| Elm works fine, for instance.
| GnarfGnarf wrote:
| I lost interest in FP when my FP solution for the Fibonacci
| series was exactly how _not_ to do it.
| Twisol wrote:
| For completeness, what was your solution? I promise not to
| judge it if you don't want me to :) but it seems like it would
| be a valuable discussion for others who might be on the fence.
|
| My solution (from another conversation on this very page) is:
| fib 0 a b = b fib n a b = fib (n - 1) b (a + b)
|
| It might (or might not) look simple, but this solution arises
| from an understanding of computation as reduction, which is
| very much not how imperative languages go about things. So it's
| really not shameful or even problematic to have arrived at a
| different solution first.
| toast0 wrote:
| You can write the closed form in FP just as well as any other
| language.
|
| Most FP languages will let you write a recursive form that
| won't blow the stack. In C, you'd need to used closed form or a
| loop if you value your stack.
| emodendroket wrote:
| Well, as alluded to, mostly because it requires you to start over
| and relearn basic things. But the compiler devs for your language
| specifically setting out to break your program is an unusual
| hurdle. Based on that alone I would never touch Elm.
| splintercell wrote:
| It's that attitude which makes elm, an excellent programming
| language to learn function programming on.
| emodendroket wrote:
| Maybe it's great for learning, but many of us wish to deliver
| a useful project and not just do something for purely
| didactic purposes
| macintux wrote:
| Which would be fine if the creators didn't also push for Elm
| to be used for production use, which is clearly a dubious
| proposition.
| bob1029 wrote:
| I have found that my best use of functional programming occurs
| within hybrid systems.
|
| When you can use either technology on a per-function or class
| basis, it really helps with adoption. Languages like C#8+ almost
| feel like cheating when it comes to mixing ideologies. Some
| developers think this sucks, but I view these complaints similar
| to those who would complain that someone might try to use a
| hammer to install a screw.
|
| The general theme in my mind is to use the imperative code to
| construct the walls of the functional matrix wherein I author the
| actual business logic as pure functions.
|
| FP for me is usually in the form of SQL, LINQ or switch
| expressions. I personally have never wanted to go all the way
| with FP. I see how you can do it in theory, but I question the
| practical engineering value of actually pursuing this. The most
| important & scary parts of our product are within this "hosted"
| functional scope.
| myWindoonn wrote:
| Good post from somebody with an overflowing teacup. Haskell's not
| magic or special; it's Just Another Programming Language, really.
| Reading their monad tutorial
| (https://gist.github.com/cscalfani/b63552922a8deb2656ecd5ec8a...)
| it doesn't sound like they actually understand monads; they don't
| know about algebraic laws or the join operation.
| zelienople wrote:
| Why is learning anything so damned hard?
|
| Mainly because we are monkeys to whom a reasonably accurate
| reductive analysis can be applied if we label the axes "asshole"
| and "idiot".
|
| It was a good blog post by a reasonably intelligent monkey who
| seemed to score low on the "idiot" axis. But some other monkey
| pegged the "asshole" axis by preventing us from highlighting the
| text so we could right-click and search to answer the primary
| question, "What is it?"
|
| Namely, what is functional programming? Even after besting the
| right-click hurdle, no one easy and succinct answer is available.
|
| The meta-analysis of this blog post therefore circles back around
| to perform a second-phase adjustment of the author's "idiot"
| score once we realize that he has done exactly what he is
| complaining about; he is a bad teacher because he did not answer
| the "What is it?" question.
|
| He seems like a reasonably nice person, so I think we have to
| leave his "asshole" score alone in the second phase.
|
| The collective effort, however, scores high on both the "idiot"
| and "asshole" axes, and this is the core of the "bad teacher"
| problem.
|
| I spent most of my long university career angry about this
| problem. Why is is that monkeys can't teach?
|
| Partly, it is because they are arrogant assholes who don't want
| to weaken their position by making it easy for others to access
| their expertise.
|
| And partly it is because they are monkeys who think more highly
| of themselves than is justified, and therefore they cover their
| ignorance with jargon, hand-waving, and obfuscation.
|
| Other than extinction, I'm not sure how to solve the problem, but
| I'm sure that the first step is by starting every lesson by
| answering the "What is it?" question succinctly and concretely,
| and, more importantly, realizing that if you can't do that, you
| should shut the fuck up and go away.
| btkramer9 wrote:
| To your point about others not teaching well to preserve their
| status, I'm sure it exists but not that prevalent. I think
| people who have known something for a long time just forget how
| to empathize with not understanding what they've known for so
| long.
|
| For this reason alone I think this is why fellow students tend
| to be much better at tutoring/helping each other instead of
| their professors.
| scns wrote:
| The experts blind spot comes to mind:
|
| https://thevaluable.dev/expert-blind-spot-software-developme...
|
| https://nscblog.com/continual-learning/understanding-underst...
|
| Dropping the judgements, assuming positive intent and trying to
| see the situation might help.
| TheRealNGenius wrote:
| It's really not
| Fiahil wrote:
| Functional Programing is hard to learn because it literally
| changes the neural pathways in your brain. Once you learn it,
| there is no going back : your grey matter will be changed
| forever.
|
| I used it a lot in the past, and less nowadays (Rust), but I
| occasionally have to teach my coworkers on basic FP principles so
| they can use and write good Python code. Simple descriptions make
| the learning more palatable and doesn't scare people ("you could
| use a Monoid here" -> "Try using a class like this, with an
| `empty` and `combine` function, here").
|
| It usually takes about 6 months of daily practice to learn basic
| FP skills and 1-2 years to go from beginner to "intermediate"
| level. Occasionally, you might encounter a FP grandmaster who
| will melt your brain in less than 2 minutes of conversation, some
| things never change.
| dtagames wrote:
| So true! It's a tough disease to catch but totally incurable.
|
| Once you have the bug, you start to pick-up _code smell_ in
| anything that isn 't functional. You see code and ask, "Why are
| we touching that?, Why are we holding onto this?" Being able to
| think in a functional style encourages you to throw away as
| much code as possible and hang-on to as few crufty elements of
| state as are minimally required.
|
| It also makes you very anti-OOPS and hesitant to define
| "classes," since these violate the first principles of
| functional.
| dingosity wrote:
| Shouldn't this article have been titled "Why Is Learning Haskell
| So Damn'd Hard?"
|
| Don't get me wrong. I like Haskell. But yeah, I learned Haskell
| because I used to sit at a desk across from Brian O'Sullivan (who
| later wrote "Real World Haskell".) And even having Brian around
| to answer questions, it still required stretching of the
| brainpan. But at least I had a guide.
| pjmlp wrote:
| It is really?
|
| Personally I think it is a matter of what teacher one happens to
| bump into.
|
| I was quite lucky to have such set of teachers for logic
| programming (Tarsis World and Prolog), and Functional Programming
| (Lisp, Miranda, Caml Light).
|
| It felt no different form other programming classes.
|
| In fact, it had higher success grades than thermodynamics,
| electromagnetism physics or the most feared of all assignments,
| data structures and algorithms.
|
| So dammed hard depends very much on the learning path.
| jasperry wrote:
| I love functional programming and I think every CS major should
| learn the key concepts of it: higher-order functions,
| immutability, purity, and how they can lead to better designs and
| more reliable software.
|
| However, I believe that even after the learning curve has been
| scaled, the task of writing code in functional languages is
| objectively more difficult in at least one way: Coding a function
| in the expression-oriented syntax of functional languages has a
| higher cognitive load than coding that same computation as a
| sequence of statements. You simply have to hold more things in
| your head.
| matheusmoreira wrote:
| > higher-order functions, immutability, purity
|
| These concepts aren't hard to understand and are actually
| incredibly useful. At some point though things get so abstract
| it's really difficult to understand what's going on. I've seen
| Haskell libraries that do things I can't explain for reasons I
| don't understand and the extremely detailed README with
| diagrams and arrows and everything somehow made it even more
| complex.
| Twisol wrote:
| > At some point though things get so abstract it's really
| difficult to understand what's going on.
|
| A lot of that comes down to extremely advanced use of
| Haskell's type system. Advanced type systems are valuable,
| and they're easier to add to FP languages, but I wouldn't
| consider them to be a fundamentally FP concept. (We see very
| expressive type systems being included in imperative
| languages like Rust and Swift these days.)
|
| I think it's useful to keep in mind that Haskell is used a
| lot for research. You don't see Java used as a research
| sandbox in the same way, so you're not likely to run into run
| into these kinds of libraries in Java. (Though, as an aside,
| I consider anything that heavily uses reflection in Java to
| be nearly as inscrutable.) It's actually impressive just how
| many of these research-level libraries are practically useful
| in some way, even if the bar to understanding them is higher.
|
| I don't think it's a universal truth that libraries making
| advanced use of type systems must be difficult to understand.
| Taking the `lens` library as an example (and I think you were
| alluding to it, anyway), there's a fairly long-running thread
| of research around what a "lens" even is, and how they fit
| into a broader domain of "optics". The `lens` library was
| created based on one particular representation of lenses, and
| the community tried to find ways to unify the various kinds
| of optics in a way that made sense to them. I think the more
| recent understanding of "profunctor optics" might give us a
| more accessible route to understanding optics in general,
| separate from the whole hierarchy of distinct optics you can
| derive from it.
| thysultan wrote:
| It's not functional programming, it's functional languages that
| go bat shit crazy with the amount of symbols they use that'd make
| looking at heliographs a refreshing pass time.
| Jtsummers wrote:
| Out of curiosity, what are the crazy amounts of symbols present
| in, say, Erlang, SML, Scheme, or Common Lisp?
| bigbillheck wrote:
| Parentheses count as symbols.
| Jtsummers wrote:
| Are there crazy amounts of them? Compared to mainstream
| programming languages?
| throwaway81523 wrote:
| We're talking about typed FP so only SML in your list really
| counts. So let's see: functors, polymorphism, higher-kinded
| types (does SML have those?), Hindley-Milner type inference,
| etc. Then for Haskell (the main topic of the linked article),
| bring in a bunch of unfamiliar algebra such as the notorious
| monoid on the category of endofunctors. It is actually worth
| understanding that. I liked this article (prerequisite: some
| exposure to Haskell):
|
| https://www.haskellforall.com/2012/08/the-category-design-
| pa...
|
| This is also good:
|
| https://en.wikibooks.org/wiki/Haskell/Category_theory
| Jtsummers wrote:
| > We're talking about typed FP so only SML in your list
| really counts.
|
| I like your sense of humor.
|
| Appeal to Wikipedia Fallacy:
| https://en.wikipedia.org/wiki/Functional_programming
|
| LISP certainly shows up in the discussion. It's even called
| the _first_ functional programming language!
| throwaway81523 wrote:
| There's not really an official definition of FP. There
| are some proposed ones that involve types and some that
| don't involve them. Mainly though, this is a thread about
| the linked article, which is about the tribulations that
| the author had learning Haskell. Most of those
| tribulations were with the type system and I think that
| matches most people's experience. You can't transplant it
| to Lisp.
| codr7 wrote:
| Common Lisp is about as functional as modern C++, it's a
| multi paradigm language by design.
| the_only_law wrote:
| Not only symbols, I've stayed away from Scala because half the
| libraries I've looked at seem to want to make their own little
| DSL the language.
| erik_seaberg wrote:
| That's the way we ought to be working. If you don't write the
| DSL, you'll have to macro-expand the DSL in your head and
| write a bunch of boilerplate which everyone will be forced to
| try to reread and maintain forever.
| nephanth wrote:
| Imho, ocaml is a way better language than Haskell when you are
| learning FP coming from other paradigms: it doesn't require you
| to learn mathematical constructs such as monads or monoids when
| you are beginning, it allows you to use imperative or OO
| constructs (though they are discouraged by the language)... When
| you are used to FP, though, more abstraction can be nicer
| PragmaticPulp wrote:
| This article is a good example of why I don't use uncommon
| programming languages for actual projects. I watched an Elm-based
| project steadily slip behind schedule while the team _insisted_
| that Elm and FP were actually going to save us a lot of time...
| eventually some day.
|
| These uncommon FP frameworks and languages can be good tools in
| the right, experienced hands. They can also be fun for side
| projects and as learning exercises. But every time I've watched
| programmers try to use uncommon functional languages for real
| projects they end up like this article:
|
| > More accurately, learning Functional Programming concepts used
| in Haskell in 3 months after having thrown out 30,000 lines of
| code on a project that was now monumentally behind schedule was
| the hardest thing I had to do in my career.
|
| When you've reached the point of being severely behind schedule,
| throwing out mountains of code along the way, and struggling
| mightily just to get basic things accomplished: It's time to
| stop. Don't double down on a _new_ language that you also have to
| learn from scratch. Pick something tried and true and get the
| work done. Revisit the functional language at a later time for an
| unimportant project or a side project, not something with a
| deadline.
|
| If the programming language or ideology has become more important
| than shipping the project, we've lost the point.
| cerved wrote:
| I wouldn't say the used an uncommon language. They build some
| kind of tool to run on top of Elm which wasn't inline with the
| goals of the Elm project (unlcear how). Seems like something
| that should've been investigated before commiting
| emodendroket wrote:
| It is inevitable that someone will use a language in the way
| the developers didn't intend, but this is the only time I've
| heard of the developers specifically setting out to break
| their language for some users.
| cerved wrote:
| that seems to be the angle presented by the author but that
| doesn't mean that is what happened
| alisonkisk wrote:
| Elm author is quite vocal about wanting people to only be
| able to do things one way. It's the reason people choose
| Elm.
| roenxi wrote:
| Also the basic pitch of functional programming is "we have
| better abstractions, you'll write better code". The basic pitch
| of something like Java is "everyone knows how to get things
| done in Java" and of Python "there is a right way to get the
| task done, and we will tell you what that way is".
|
| There is a fundamental mindset here that the Functional
| languages aren't task-first. Not in the languages, mind, it is
| in the community. And the tasks themselves can be so simple
| once the abstractions are under control that people don't write
| tutorials about the task.
|
| It is visible in this article - the Haskell community is trying
| to convince this guy that he needs to know a wall of jargon
| from a relatively obscure branch of maths in order to program
| effectively. They may or may not be correct, but it is going to
| be a while before his attention makes it to the task at hand.
| PragmaticPulp wrote:
| > It is visible in this article - the Haskell community is
| trying to convince this guy that he needs to know a wall of
| jargon from a relatively obscure branch of maths in order to
| program effectively. They may or may not be correct, but it
| is going to be a while before his attention makes it to the
| task at hand.
|
| This seems to be the core problem in the communities, like
| you said: a tendency to believe that time spent learning the
| language or learning concepts or fighting with libraries or
| struggling with documentation doesn't actually "count"
| towards time spent getting the job done.
|
| I think this plays into our tendency to view learning and
| education as investments rather than costs. That may be true
| on a personal level when using your own time, but using your
| employer's time to experiment with difficult new concepts and
| languages when you have a deadline approaching (or long since
| past) is not cool.
| laserlight wrote:
| > using your employer's time to experiment with difficult
| new concepts and languages when you have a deadline
| approaching (or long since past) is not cool.
|
| To defend the counterpoint, artificial scarcity is abundant
| in the industry. Deadlines always approach, projects are
| already late. If employees don't learn and improve on the
| job, employers will be happy to replace them.
| whateveracct wrote:
| > using your employer's time to experiment with difficult
| new concepts and languages when you have a deadline
| approaching (or long since past) is not cool.
|
| It's in fact very cool. I get to take those skills with me
| when I leave in a few years :)
| Terretta wrote:
| > _using your employer's time to experiment with difficult
| new concepts and languages when you have a deadline
| approaching (or long since past) is not cool._
|
| As kindly as I can put it: I'd argue that within this
| sentiment are the foundations of everything wrong with the
| ecosystem of professional software engineering.
|
| Let's start with, if you don't let people learn on the job,
| you have to have at least 20% annual turnover to be only 5
| years behind the knowledge curve.
|
| At 10% turnover, you're 10 years behind. Managers think
| people shouldn't be learning on company time, HR tells the
| board lower turnover is a goal.
|
| Inevitable next step is pausing _all_ productive work to
| undertake a "Digital Transformation(tm)" to try to replace
| 20 years of old tech. But the firm won't know how.
| IncRnd wrote:
| >> using your employer's time to experiment with
| difficult new concepts and languages when you have a
| deadline approaching (or long since past) is not cool.
|
| > As kindly as I can put it: I'd argue that within this
| sentiment are the foundations of everything wrong with
| the ecosystem of professional software engineering.
|
| Almost all Software Engineering, as practiced, is not a
| form of engineering in any way. Many times Software
| Engineering is really a bunch of commodity workers, who
| are learning, assembling commodity components that don't
| really work, under the oversight of a more senior
| developer who helps everything not fall apart.
| Twisol wrote:
| You might be interested to read Hillel Wayne's crossover
| project, where he interviewed a number of people who had
| worked in traditional engineering roles as well as in
| software development.
|
| https://www.hillelwayne.com/post/are-we-really-engineers/
|
| The upshot is that "engineering" isn't the paragon of
| excellence we like to think it is. Whether or not you
| agree, it's a good read!
| IncRnd wrote:
| Thanks!
| AlexCoventry wrote:
| I think this problem is specific to the Haskell community.
| No one's going to tell a brand-new Clojurist that they need
| to learn about reducers.
| cutler wrote:
| Agreed. Clojure is the most productive language I've ever
| used.
| emodendroket wrote:
| I'll say this though: functional techniques really can save a
| lot of time. I'm not sure I'd recommend Scala for a new project
| if you don't have Scala experts already, but I apply ideas I
| got from my experience using it to projects all the time.
| isbvhodnvemrwvn wrote:
| The question then is whether it was functional programming
| that actually made the difference, or the people who had
| enough perseverance and skill to actually learn Scala in the
| first place running the project.
|
| I've found that people who go out of their way to learn
| things like that would be more productive regardless of the
| language itself.
| dgb23 wrote:
| That's certainly a big part. The other one is less obvious,
| but is one that shines through this article as well. Once
| you learned a functional language or any language that is
| well designed (for me that typically incorporates
| functional and possibly logic and relational paradigms)
| then you'll be more confident and productive than before
| and will have a hard time to justify using a tool that is
| inferior other than adherence to the lowest common
| denominator.
|
| I'm sure this can be observed with any profession. A good
| cook can work with a cheap knife and mediocre ingredients,
| but give them a nice set of professional kitchen tools and
| fresh, tasty vegetables and they will happily cook you a
| meal that makes your evening.
| invalidOrTaken wrote:
| >The question then is whether it was functional programming
| that actually made the difference, or the people who had
| enough perseverance and skill to actually learn Scala in
| the first place running the project.
|
| Oof, it may indeed be the second, but what do _they_ get
| out of the deal?
|
| A lot of FP programmers _refuse to go back_ , simply
| because it feels _nicer_.
|
| It's a hell of a lot easier to "persevere" on a project
| when your language doesn't make you want to dig your eyes
| out with a spoon.
| isbvhodnvemrwvn wrote:
| I agree, but then you should focus on hiring people with
| these specific predispositions, and not trying to teach
| your developers FP from scratch.
| pjmlp wrote:
| Depends on the project, that is exactly what feels to me
| sbt or scalaz.
| chii wrote:
| a good language would allow you to express thoughts that
| are difficult in another language. But this presumes that
| you have those thoughts to express in the first place. If
| you don't, the language isn't gonna magically be able to
| give you the ability to have those thoughts.
|
| So learning functional languages is both learning the
| language, but to also improve your cognitive capabilities
| to have more thoughts.
| emodendroket wrote:
| Well, the ideas I liked, stuff like deferring side effects
| and avoiding state, were functional ideas. You see a lot of
| functional concepts and constructs bleeding out into
| mainstream languages (just look at the last few C#
| releases, for instance, which look like a list of features
| borrowed from Scala), which I think will be their legacy
| more than widespread adoption.
| wyager wrote:
| FP is absolutely way more time-efficient for most kinds of
| projects, _if you know what you're doing_. Switching without
| having sufficient background first is probably not a good idea
| though.
| taeric wrote:
| This somewhat annoys me. "Knowing what you are doing" is time
| efficient. Regardless of what tooling you have.
| brightball wrote:
| The flip side is maintainability, which gets much simpler
| long term with FP.
| taeric wrote:
| Do you have evidence showing this? The few long term
| maintained programs I am aware of are decidedly not what
| one would call modern functional.
|
| (Granted, the most ported and maintained software I know
| of is either Linux or SCUMM.)
| hvs wrote:
| This is a statement that requires some sort of citation.
| Extraordinary claims and all that.
| wyager wrote:
| I know what I'm doing in many languages, and I'm uniformly
| more productive with the FP ones. The only time I'll reach
| for a non-FP language is if I'm forced to for work or if
| I'm working on an embedded system with no allocator.
| taeric wrote:
| Is this confirmation/survivor bias, though?
|
| I would love to know that there is a panacea that
| automatically improves productivity. Unfortunately, I
| haven't seen one in my career, as yet.
|
| I am certainly more happy in many functional languages.
| And I can see happiness contributing to some. But I can't
| count that as data, without RCTs or something similar.
|
| I'm not going to go so far as to claim that computer
| science isn't science. But I do fear that there are more
| claims than there are checks in our industry.
| wyager wrote:
| I wouldn't say it "automatically improves productivity" -
| I suspect it might be limited to more intelligent and/or
| mathematically inclined programmers. That said, I think
| for many programmers not using it is a huge and pointless
| missed opportunity. This is one of those visibly high-
| return arbitrages that it pains me to see go unexploited.
| taeric wrote:
| I certainly don't want my criticism to be a call to avoid
| functional programming. I just get an uneasy feeling when
| I see it over sold, as well.
| alisonkisk wrote:
| "knowing what you're doing" is extremely hard in FP, as per
| the experience of many many productive imperative/OO
| programmers who tried.
| bsder wrote:
| > FP is absolutely way more time-efficient for most kinds of
| projects
|
| I absolutely do not agree.
|
| FP binds your _particular_ choice of implementation to the
| code architecture. FP actually makes refactoring in the small
| trivial and refactoring in the large _ferociously_ difficult.
|
| A good example would be a program that runs fine suddenly now
| needs a "timeout" on an operation. FP implementations now
| need to thread the notion of time from somewhere near the top
| of the implementation the whole way down the chain to the
| function that needs "time".
|
| This is painful.
|
| An imperative programmer throws in a global time variable,
| possibly a local timeout variable and gets on with life.
|
| Now, if I'm trying to manage a high-complexity codebase, I
| will probably eat the FP penalty. Having complete
| determinism, decoupling, and visibility in, say, a network
| stack makes debugging possible that will be very difficult
| with sorta-state smeared across a bunch of variables at
| various level of hierarchy.
|
| However, I accept and acknowledge that I am making a
| tradeoff.
| Jare wrote:
| That's the problem with "uncommon": how do you obtain that
| background and how do you learn what you're doing? (of
| course, not just you - you, the entire team, and future
| hires)
| throwaway81523 wrote:
| The same way you learn anything else that is difficult:
| time and practice, and start with fundamentals. You can't
| put it on any work-related critical path until you have it
| down solid.
| Jare wrote:
| I mean in the context of an existing company / team of
| nontrivial size. Most cases I know of, the uncommon
| language was there from the days of it being a personal
| or 1-person project. For other types of tech (e.g.
| infrastructure) sometimes the new/different capabilities
| are such a defining feature that the lack of familiarity
| is not as scary. But in programming languages, you can
| fundamentally do pretty much anything in existing and
| well known ones.
| throwaway81523 wrote:
| Have fun writing a web app in assembly language ;). Yes
| it's been done, but not often, and for good reason.
| Haskell is sort of a special case: it's best suited for
| writing compilers, but has been pressed into just about
| everything else because people are into it for its own
| sake.
|
| Yes if you're running a C++ shop and someone leaves
| behind a small program in Haskell, you're probably better
| off reimplementing it than becoming or hiring a Haskell
| guru just to maintain that thing. That's a question of
| _whether_ to learn Haskell, not how to learn it. In the
| case of the linked article, the author was the one who
| decided to get the company involved with FP, and gave his
| thoughts on whether it was worth it.
|
| I can certainly support the idea that someone juggling
| all the plates required to keep a company running, has no
| time to embark on a deep and nerdy self-education project
| in something as abstruse as FP. Better to keep it at the
| level of a side interest or hobby until you're
| comfortable with it, before even thinking of doing
| anything important with it.
| whateveracct wrote:
| a good attitude and some elbow grease
|
| most "failed" FP projects I've seen mostly lack the former
| - often due to managers or engineers that come on the
| project after it first hits prod
|
| then comes the rewrite to add a notch in said managers' and
| engineers' belts
|
| then the original FPers leave and now there's systems in
| prod with little to no people who can work on it. that
| rewrite suddenly got a lot more business-critical!
|
| the original FPers weren't as PM-savvy, so the rewrite is
| successful despite having less functionality and still
| taking a year or more. doesn't matter - the savvier
| managers and engineers know how to set goals & milestones
| that they know they'll hit and can say that they hit when
| evaluating the project's success
|
| This is just a summary of my years of experience as an FP
| professional. I've seen this happen 3+ times across 3+
| companies.
|
| ---
|
| Haskell is by far the most worth-it skill I've cultivated.
| It wasn't easy but I really do do a 10x job on my personal
| projects in large part due to it. It's just not a good
| language to use in a corporate setting. It's better to get
| paid big bucks to be less productive. Save the technical
| brainpower for things you yourself find valuable :)
|
| (and I sneak Haskell in all my jobs anyways - scripting,
| for instance - so I still develop my Haskell knowledge on
| company time & dime, despite the language being all-but-
| banned by the higher-ups)
| wyager wrote:
| My previous employer would teach new employees to use a
| functional language from scratch and people would be
| productive in 2-3 weeks. I don't think it's actually that
| difficult in reality.
| guerrilla wrote:
| I think it's more that you shouldn't use a tool that you're
| incompetent at. It has nothing to do with how common or not it
| is. Just know what you're doing or don't do it.
| PragmaticPulp wrote:
| > I think it's more that you shouldn't use a tool that you're
| incompetent at. It has nothing to do with how common or not
| it is.
|
| These two points are closely related, though.
|
| Common tools will always have more available programmers,
| more documentation, more tutorials, more help, more
| libraries, more maturity.
|
| We had a server written in a functional language at a company
| I worked at. It was fine, but when the two people who wrote
| it left the company it became a huge pain point to even hire
| someone to work on it. Consultants knew this and demanded
| exorbitant fees for basic work on the project.
|
| Eventually we just rewrote it from scratch in a common
| language and saved a huge amount of time and money compared
| to trying to build teams and schedules around this obscure
| language.
| guerrilla wrote:
| > more documentation, more tutorials, more help, more
| libraries, more maturity.
|
| Haskell's got all that but I can't argue with it needing
| more programmers.
| [deleted]
| cerved wrote:
| which language?
| AzzieElbab wrote:
| What if I told you that common languages are rapidly
| adopting futures from functional languages? Go being a
| notable exception.
| PragmaticPulp wrote:
| > What if I told you that common languages are rapidly
| adopting futures from functional languages?
|
| I use functional paradigms in mainstream languages. No
| need to be snarky or sarcastic.
|
| That's not what this article is about, though. Using Elm
| and Haskell for projects is not mainstream.
| Jasper_ wrote:
| As far as I know, the Future concept for async/await
| started with Twisted's Deferred, which is a framework for
| Python. It's not really from functional land.
| cerved wrote:
| futures have been around since the 80s afaik
| nextaccountic wrote:
| Futures were first proposed in 1976, in a book called
| "The Impact of Applicative Programming on
| Multiprocessing". [0]
|
| Applicative programming is an older term for functional
| programming[1], but note this isn't pure functional
| programming like in Haskell; it's functional programming
| like in Scheme and Javascript.
|
| [0] I can't find a pdf of the book, but it was mentioned
| here https://en.wikipedia.org/wiki/Futures_and_promises -
| the book calls it promises
|
| [1] https://en.wikipedia.org/wiki/Applicative_programming
| _langua...
| rowanG077 wrote:
| I don't think python invited a single thing tbh.
| Igelau wrote:
| Really I think the mistake there was not forking Elm. Maybe the
| fork wouldn't have been popular long term, but at least they'd
| ship.
| PragmaticPulp wrote:
| > Really I think the mistake there was not forking Elm.
|
| Forking a framework and trying to maintain a new, separate
| open source project is a huge burden. There is no way that
| would have fixed their problems of being behind schedule, but
| it definitely would have permanently worsened their
| maintenance overhead.
|
| They needed to scrap the alternate language/framework plans
| and return to something safe and proven as soon as it became
| obvious that they were too far off track. Continuing to
| double down on commitments to unpopular frameworks (or worse,
| creating your own niche fork to maintain) would only worsen
| the problem.
| adregan wrote:
| I agree. Assuming this article is about the author's
| experiences in early 2019, Elm has only had one release since
| then. They wouldn't have missed out on much at all by
| shipping with a forked compiler but would have gained a lot
| of time to migrate.
|
| The fork wouldn't necessarily need to be public either.
| dimator wrote:
| Rather than forking elm, there's purescript, which is unlike
| elm in all the restrictive ways. It seems to have regular
| releases and plenty of packages as well.
|
| https://www.purescript.org/
|
| https://pursuit.purescript.org/
| sam0x17 wrote:
| Yeah I was literally expecting the next paragraph to be "and
| that's how elixir was born!"
| exdsq wrote:
| Mandatory Hitler reacts to Functional Programming comment
|
| https://youtu.be/ADqLBc1vFwI
| pjc50 wrote:
| It's "monad is just a monoid in the category of endofunctors": if
| you don't understand something, here is an explanation in terms
| of other things you understand even less.
| AzzieElbab wrote:
| Monad is a thingie that lets you sequence computations in the
| same context. Context being something like Future or Stream or
| List
| kayodelycaon wrote:
| I'm not sure if this is supposed to be sarcastic or not but
| it doesn't make any more sense to me.
| yudlejoza wrote:
| One way to think of a monad is through the example of a
| shell (e.g., bash) pipeline:
|
| # cat data.csv | process-1 | process-2 | ... | process-n >
| final-output
|
| Imagine you have this pipeline that already works for
| data.csv. But now you have data2.csv which has some
| difference (e.g., some values are null, while the original
| data.csv had no null values).
|
| Monads are an approach to making the existing pipeline work
| (with minimal changes) while still being able to handle
| both data.csv and data2.csv. The minimal changes follow a
| strict rule as follows (this is not a valid shell command
| anymore):
|
| # wrap(cat data.csv) ] process-1 ] process-2 ] ... ]
| process-n > final-output
|
| In other words, only two kinds of changes are allowed:
|
| - You can bring in a wrap function, that modifies the
| entries of the given csv data.
|
| - You can bring in a new kind of pipe ']' instead of '|'
|
| The idea being, the wrap function takes in original data
| stream, and for each "unit" (a line in the csv file, called
| a value) produces a new kind of data-unit (called monadic-
| value). Then your new pipe ']' has some additional
| functionality that is aware of the new kind of data-unit
| and is able to, e.g., process the null values, while
| leaving the non-null values unchanged.
|
| Note, you didn't have to modify any of the process-1
| through process-n commands.
|
| BTW, the null value handling monad is called the 'maybe
| monad' (and of course there are other kinds of monads).
|
| If you make the existing pipeline work in this way, you
| essentially created a monad to solve your problem (monad
| here is the new mechanism consisting of the new value, and
| the two new changes, the wrap function, and the new pipe).
|
| edit: There may be a need to also modify the '>' mechanism.
| But I think that is not essential to the idea of a monad,
| since you could replace ">" with "] process-n+1 >" (i.e.,
| you created a new outermost function 'process-n+1' that
| simply converts the monadic-values back to regular values).
|
| edit 2: If instead of handling null-values, the purpose is
| to "create side-effects" e.g., at every pipe invocation,
| dump all/some contents of the data into a log file, then
| the kind of monad you end up creating would be something
| like an "I/O monad".
| chii wrote:
| it doesn't make sense to an imperative programmer because
| "sequence computations" is like water to a fish. the idea
| that computation isn't always sequenced doesn't occur to
| someone who hasn't encountered functional programming.
| kayodelycaon wrote:
| Not sure what you mean by that. Threaded and event-driven
| systems don't necessarily have a predictable sequence.
| Same with data flow through any non-trivial web
| application using background processing.
|
| I've worked on systems that run through a chain of
| background workers. Each job had a complete list of
| operations (one per worker) to preform. When each worker
| finished, it posted the job back to the general queue
| with the new state and one less operation to preform.
|
| All programs are eventually sequenced. You can't work on
| data that doesn't exist yet.
|
| I'm pretty sure I don't lack the ability to understand
| what your talking about. I am sure I don't know what the
| words you are using mean.
| ModernMech wrote:
| As an educator, I get to see many young programmers learn
| about functional programming usually around their
| sophomore year of college. They've never used threaded,
| event-driven, dataflow, or similar systems. All they know
| how to write are single-threaded Java programs, and their
| perception is that programs are "a list of statements
| that tell a computer what to do, in order".
|
| They are especially uneasy about the concept of lazy
| evaluation. It goes against everything they know about
| programming - that you write a line of code, it's
| executed, and you move on to the next line of code. With
| lazy evaluation (as in Haskell) it's an uphill battle
| getting them comfortable with the idea of writing a line
| of code that will be executed at some unspecified point
| in the future. For many students, this can be a mind-
| bending realization.
| mdoms wrote:
| Do you guys really look at a sentence like this and think,
| "yup, that clears it up"?
| nowherebeen wrote:
| These context you list are higher order kinds.
| wsc981 wrote:
| This is actually a very understandable explanation, though
| maybe 'thingy' should be replaced with 'mechanism'.
| dustinmoris wrote:
| Observation from the real world:
|
| Functional programming seems to be extremely easy if you have
| never learned imperative programming first. I have seen beginners
| grasp FP much faster than OOP and write production ready code
| only after a few weeks/months of learning whereas beginners need
| on average multiple years to learn "production ready" design
| pattern style OOP.
|
| On the other hand I have observed some of the best OOP developers
| really struggle with FP. It's not that they find FP hard to
| learn, they find it _really hard_ to unlearn OOP and the thinking
| that the way things are done in OOP is the holy grail of good
| software design.
|
| For example, only recently there was this blog post trending on
| HN (Am I stuck in a local maximum -
| https://blog.ploeh.dk/2021/08/09/am-i-stuck-in-a-local-maxim...),
| which was triggered by a "blue tick" OOP programmer (tastapod on
| Twitter - inventor of BDD) making false statements about FP
| because he seemingly struggled learning it and wasn't able to
| work out how to program without mutations. He came to the
| conclusion that all functional programmers actually use mutations
| by default and immutable data structures are not common in FP at
| all. It was a completely unfounded assertion and clearly one made
| from frustration by someone who was so hard wired into OOP
| programming that they couldn't adapt to the FP way of thinking.
| It was a prime example of an "old dog" (citing the original
| article) finding FP harder than the new guys.
| jacquesm wrote:
| Yes, this is very true. It took me a lot of time 'unlearn' bad
| habits about state and side effects before functional
| programming really clicked. The interesting bit is that it made
| my other programs better as well, because I still find myself
| avoiding mutable state and impure functions.
| dnautics wrote:
| I'd personally say it's less about unlearning statefulness
| and learning what the alternative tools are and not be
| bullheaded and kick and scream about not having the tools one
| is used to, e.g. map and reduce vs for and while.
|
| Once you learn how to use them, their utility and benefit
| (they explicitly limit the scope of the changes in the loop
| and reduce mental overhead) become clear. But a lot of people
| never get past "why can't I have a for loop" and don't get
| there.
| jacquesm wrote:
| Map and reduce immediately clicked, the state thing had me
| for the longest time ('how do you generate output, how do
| you get a real world effect from a function'), those seemed
| to me to be far more magical in the FP world than in the
| step-by-step alteration of the environment that I was used
| to from imperative programming.
|
| It also seemed to map harder onto the real world than IP,
| where instructions about piecemeal alterations seem to be
| the way of the world.
|
| It really clicked for me when I started to think in terms
| of transformations, where each function performs a
| transformation of the input on the way to some output. This
| allows you to be 'pure' most of the way and to limit input
| and output to the top layers of the program, where they
| should be (should in my opinion).
| agumonkey wrote:
| Thre's a little bit of psychological esoterism too, fp is very
| minimal, OOP gives people some new mystery rope to hang
| themselves with. verbose syntax, procedures to follow, it's
| probably psychologically a better impedance matching than 'a ->
| 'a -> b -> ('a -> 'b) where people have to hold very very
| evanescent ideas floating in the air without as much ways to
| play with them.
| motohagiography wrote:
| I fail to learn Haskell about once every 5 years and sometimes I
| think of functional languages as not languages for expressing
| concepts, but more like a musical notation that denotes a set of
| abstractions mapped to an underlying ontology made from things
| you just train yourself on with practice - and then use the
| functional language as a lookup reference to until you can in
| effect "sight read," or compose those underlying elements to the
| page. The algebra and category theory are the true instrument,
| and the language is the composition notation tool. Whereas with
| OO and imperative programming, the imperative or OO language
| itself is the instrument or tool that you can just pick up and
| bang away on and music will come out. To extend the metaphor, OO
| is an instrument on which you can play a canon like "row your
| boat" without knowing how to write one, some, or all of them.
| It's lovely that we have these tools for specifying and composing
| functions, but perhaps the gap is in effectively expressing and
| teaching the underlying ontology. Maybe as a writer, my next
| attempt should be to write that explanation of it as I go.
|
| The most trouble I had with Haskell was pronouncing statements
| after reading them, which prevented me from composing the ideas
| in my head because the syntax doesn't give you a lot of hints.
| It's like trying to parse calculus without names for the letters
| in the greek alphabet. Most people are proficient in their own
| written languages, and they are capable of mapping ideas to
| abstractions, but if there is not a way to express those ideas
| lexically in their language, most are going to stumble.
|
| The incomplete and error prone explanations by novices that the
| author refers to also create an artificial conceptual barrier,
| but mostly because there is always the hint and implication (or
| perhaps just personal anxiety) that you are not writing _real_
| functional programs and that your naivety is accumulating a
| hidden sunk cost that you will eventually be exposed for and made
| ashamed of because you aren 't a category theorist, which is a
| consequence of this mostly aesthetic idea that functional code is
| about competing to advance knowledge in a science and not just
| making stuff you enjoy or people like. The clostest thing I found
| to a kind of _function-punk_ where you could just bang away on it
| because it was fun was the excellent
| Learnyouahaskellforgreatgood, but it focused on the notation less
| than the underlying ontology - e.g. the instrument - and what I
| think I might need is more of a _category-punk_ that provides the
| equivalent to composition with a few concepts, and then add the
| notation to those.
|
| Not sure there's another attempt in me, but anyway, provocative
| article about something so important, and that I think ultimately
| FP will really advance the way people think about the world, if
| only in another generation or two.
| del_operator wrote:
| Teaching someone to abstract out a name for something they want
| to do takes lots of practice, but then when they are pushed to
| have to abstract can lead to decision paralysis around when to do
| it. Having folks practice this together and feel out the nuances
| helps a lot. Control flow is also a tricky early concept for any
| new programming setting, but also, learning to compose is too.
| For some students tackling control flow and composition early by
| explicitly composing abstracted funcs feels great. However, I've
| oft seen many of my students want to get granular with control
| flow for a long while before they abstract or utilize many
| abstractions, probably because their mental model of what they
| want to do is stepping through each detail of an example they
| have in mind. Another component for andragogical learning is to
| just sell the WHYs of functional patterns: why care, why
| remember, why it's helping, why they should just give it 5, why
| it's ok to forget, et cetera. Learning and jumping straight into
| synthesizing, evaluating and analyzing code for a potential
| production setting has been difficult with a loose understanding.
| You need good scaffolding in your backlog, lots of time,
| patience, context sharing, and resourceful experts to turn to
| check your understanding and promote good tooling/solutions in
| the ecosystem. I saw this when my team switched to elixir. I saw
| this when my team stitched to K8s. Lots of delays I'm happy we
| worked through. Pairing a lot helped through it
| Igelau wrote:
| Lisp has always seemed like the most teachable FP language to me.
| I imagine it would be hard to start elsewhere.
| cerved wrote:
| Haskell seems like a terrible language to start with
| wyager wrote:
| Disagree. I think it's a lot easier to learn than something
| like C++ or Java, which a lot of people start with. People
| just tend to forget how much they struggled with these very
| complicated languages when they were getting started.
| cerved wrote:
| I meant of the functional languages
| Igelau wrote:
| You make a good point. It's been a long time since "do a
| cout" seemed like a reasonable way to think about output in
| C++.
| abeppu wrote:
| Yeah, it seems weird that the author latched onto some things
| as part of their definition of "functional programming" which
| aren't really required. I still find SICP to be an impressive
| self-contained foundation for functional programming, and
| "Functor" and "Monad" aren't mentioned as named concepts.
|
| Is there a better name for the domain the author is talking
| about? "Type-driven functional programming"?
| rightbyte wrote:
| FP with dynamic scoping?
|
| Lisp is not a FP language anymore than C.
| Jtsummers wrote:
| Sure it is. Using the "Appeal to Wikipedia Fallacy":
| https://en.wikipedia.org/wiki/Lisp_(programming_language)
|
| Most Lisps are multiparadigm, covering at least the
| functional and procedural paradigms. Going to Common Lisp you
| can add OO to the mix. It is a severely constrained notion of
| FP that manages to exclude the first functional programming
| language from its definition.
| lispm wrote:
| Lisp only has dynamic scoping? C comes with first class
| function objects, closures, ... ?
| legobmw99 wrote:
| My two cents is that anything is hard to learn without an
| application you can test your knowledge against. It's always hard
| to learn language X until you go ahead and build something in it.
|
| Functional programming is hard because in a lot of cases,
| especially ones beginners encounter, the imperative solution is
| simpler. Purity and types are things I think you only truly
| appreciate when you're writing large or complicated programs. I
| wasn't able to really grasp FP (beyond using things like map() in
| Python) until I took a compilers course which used OCaml, and the
| ability to pass around and destruct these very complicated
| immutable trees was a very natural problem to tackle in the
| domain
| throwaway81523 wrote:
| > My two cents is that anything is hard to learn without an
| application you can test your knowledge against. It's always
| hard to learn language X until you go ahead and build something
| in it.
|
| If it's something really new and different, like Haskell is to
| an old school imperative programmer, I think the opposite
| approach is best. Treat it like a topic in math, start from
| zero, work out small problems to exercise the basic concepts,
| then start putting them together.
|
| Immutable data structures are another new and shocking thing,
| but less complicated than fancy typed FP is. Start with seeing
| how you can "update" the first element of a linked list by
| making a new first element and linking it to the existing tail.
| Then see how AVL or red-black trees let you do something
| similar with tree nodes in log(N) time, so you can use those
| instead of hash tables without a monstrous slowdown. That's
| probably all you need, but the next thing after is probably
| Chris Okasaki's book Purely Functional Data Structures. It is
| pretty readable once you've seen some basics.
| chadcmulligan wrote:
| Maybe one of you functional gurus can answer this - One of the
| problems I have with functional programming is how do you handle
| multiple data structures on a single thing. For example - say you
| have a drawing program, with say just one shape - a square. Now
| to make it fast when the user clicks somewhere you'd have a data
| structure like a k-d tree that can find your shape quickly. Now
| you also have another structure a list of the shapes, because you
| don't want to put them in the k-d tree, you update both
| structures when shapes change. You'd also want other structures
| for say undo/redo. I can't see anyway to do this in functional
| programming. Same applies to database style programming.
| hvocode wrote:
| That's not that hard in an FP language. I routinely write code
| with multiple structures referring to the same thing. My usual
| solution is to have an identifier for the thing that indexes
| into an array or map, and then the other structures contain
| that ID instead of the object itself. It's basically a pointer
| like I'd use in any other language. The details and choices for
| how to represent the IDs and structures is usually application
| specific, but that's true in any language: how you do something
| should be the choice that best fits your problem. There isn't
| anything about functional programming that makes it impossible
| or particularly difficult.
| chadcmulligan wrote:
| ok, cool, would you know some sample code somewhere you could
| point me to? Just to see an example, always thought you
| couldn't do this.
| Mikeb85 wrote:
| Functional programming is hard because some proponents of it
| spend more time on theory and proving why you should use FP than
| simply doing things with it. That's why most things shipped with
| FP is created with languages like Ocaml, Scala, JavaScript,
| Clojure, etc... You know, functional but more pragmatic and
| multi-paradigm.
| yodsanklai wrote:
| It's not hard at all. It's routinely taught to beginners.
|
| However, it's not a silver bullet. I found that basic software
| engineering principles are way more important than the language.
| I've seen extremely messy OCaml code and super clean C code. What
| is important is how the code is organized at high level. Whether
| you use a for loop or a fold, an error monad or an exception
| mechanism matters less.
|
| I'm also wary of functional programming gurus that tend to over-
| abstract things and use all the language latest features, making
| code very hard to read.
|
| Also, when developing in a niche language, you tend to miss
| important tools and need to rely on unstable third-party
| libraries.
|
| I used to be quite enthusiastic about FP, but I think I'd stick
| with more mainstream languages unless there's a good reason not
| to.
| swiley wrote:
| Programming is about clearly communicating theory.
|
| Mariners use "port" and "starboard" for vehicle relative
| directions not because it's "cool" but because it's clear and
| unambiguous. Problem decomposition works the same way: some
| problems decompose better with FP (I would argue databases do)
| some with OOP, some with EF etc. The more you know the clearer
| code you can write and the faster you can extract the theory
| from other people's code.
| IIAOPSW wrote:
| What makes you say "port" and "starboard" are more clear than
| "front" and "back"?
| swiley wrote:
| The alternatives are left and right respectively. They're
| more clear because left and right are usually relative to
| the speaker or listener who may be facing each other and
| are often moving around.
| byroot wrote:
| It's not "front" and "back" it's "left side of the boat"
| and "right side of the boat".
| IIAOPSW wrote:
| Oops.
| WalterBright wrote:
| More correctly, the "left side of the boat" and the
| "other left side of the boat."
| caconym_ wrote:
| a) They refer to left and right, not front and back (which
| I believe would be "forward" and "aft").
|
| b) With the possible exception of "forward", if you hear
| one of these words you always know it's specifying a
| direction relative to the direction the boat is pointing,
| which is not true for "left" and "right".
| reverseblade2 wrote:
| this 3d bin packer is fully coded in F# and I wouldn't be able to
| do so without it.
|
| https://bindrake.com/
| [deleted]
| bobcostas55 wrote:
| One aspect I don't see mentioned very often is that the FP model
| of computation is completely different from the model of the
| underlying hardware, which makes it very difficult to reason
| about things (and often involves putting blind hope in the
| compiler).
| macintux wrote:
| I would dip my toes into FP occasionally (but very, very briefly)
| for years. I bought a book on Scheme in 1995, to give you a sense
| of how long I wandered in the wilderness.
|
| It wasn't until I discovered Erlang in 2012 (thanks, _Seven
| Languages in Seven Weeks_ ) that I finally found the motivation,
| aided in no small part by the fact that it's a very simple
| language and it's designed for server programming, where I've
| always been happiest.
|
| I still haven't graduated into category theory or type theory. I
| still don't know the difference between a monad and a monoid. But
| functional programming really speaks to me, because I have an
| old, tired brain and I need pure functions wherever I can employ
| them to keep things straight.
| stadium wrote:
| Pure functions concept was a breakthrough for me too. As a
| design pattern they are wonderful, there is so much less mental
| context to keep track of.
|
| Now whenever I see mutated variables and class attributes, or
| random side effects besides reading/writing to a database, it
| kinda makes me cringe and think it's a "oh here we go" into a
| rabbit hole just to understand what the code is doing. 9/10 the
| code does what it's supposed to, but the mutations and side
| effects makes understanding and extending it so much harder.
| exdsq wrote:
| A monad is just a monoid in the category of endofunctors
| stackedinserter wrote:
| Probably because every single FP tutorial is very far away from
| real tasks that average software developer deals on everyday
| basis.
|
| They describe pure functions and categories of endofunctors,
| while I have tasks like "invoke this stateful external API if
| that stateful external API returns specific values".
| jqgatsby wrote:
| His daughter's question "Why do we use functions?" is something I
| found myself asking during my math undergrad, and no one could
| give me a straight answer.
|
| To answer it to my own satisfaction, I eventually arrived at a
| form of predicate logic so I could directly experience how
| cumbersome it was to try to express everything that way. I liken
| it to trying to speak in a language that lacks a definite
| article: doable, but way more verbose.
| polishdude20 wrote:
| I always thought of functions as just boxes. We like to put
| similar things in boxes because that lets us remove the
| complexity of having to manage many similar things at once.
| When you can just say "this group of balls here needs to be put
| in the closet" you don't need to think or know that one is a
| tennis ball, one is a basketball and one is a softball. A
| function to me is just a way to wrap up a complicated idea or
| task into a box. It's what we already naturally do with
| everything in our lives.
| dtagames wrote:
| Indeed, but _functions_ are not the same thing as
| _functional_ programming. (We reuse so many words in this
| field!)
|
| What you're describing are regular functions. If those
| functions hold a _state_ , they're not functional; they're
| procedural. For example, a function that holds onto a counter
| and increments it by some value that is passed in _cannot_ be
| functional because the counter exists in a hidden state,
| unknown to anyone else and unpredictable until runtime. This
| is what Backus was trying to fix.
|
| A _functional_ version of that same function would need two
| parameters, one for the amount to increment by and a second
| one for the counter 's current value. Often, a function can
| be rewritten in the functional style and thereby eliminate
| state (at least from that function).
|
| Whew!
| polishdude20 wrote:
| So at some point up in the heirarchy, you're keeping track
| of that counter. So there will be a parent of the
| incrementing function which is itself not a function
| because it keeps state. You could say your top level
| program is not a function because it keeps state.
| Thiez wrote:
| Not neccessarily, when your program is (tail-)recursive
| you can carry the "current" value along without ever
| really mutating it. Haskell has the State monad which
| doesn't require any impurity.
| scns wrote:
| In Nim you declare func and proc IIRC.
| Igelau wrote:
| This is how I answer my kids' questions. "Why? Why? Why?"
| Buckle up, kid, we're going down the rabbit hole. They usually
| get bored before I do and have learned to back off when I slip
| into presentation tone.
| scns wrote:
| Feynman gets asked how magnets work:
| https://www.youtube.com/watch?v=MO0r930Sn_8
| asimpletune wrote:
| A function is just the concept of a thing that maps from a
| domain to a range.
| chimen wrote:
| A function is a verb to me. It explains an action, just one.
| emodendroket wrote:
| Lots of languages lack definite articles without being notably
| more verbose.
| Zababa wrote:
| I really think we should go back to calling things that are not
| pure functions "procedures" or maybe "subroutine".
| darksaints wrote:
| It's just the Haskell family of functional programming languages
| that is hard to pick up. There are plenty of functional language
| families that are quite easy to understand and much more
| pragmatic:
|
| * ML - includes SML, OCaml, F#, Scala, and Rust
|
| * Lisp - includes Common Lisp, Racket, Scheme, Clojure
|
| * Actor Model - includes Erlang, Elixir, and Pony, as well as
| other languages that have actor model systems at the library
| level
|
| You'll find endless sources of opinions on why the Haskell family
| is so hard to use well. My personal opinion is that most
| languages create abstractions with concrete types of problems in
| mind. Haskell created abstractions with other types of
| abstractions in mind. If you ask the question "what is a monad
| used for?", the average Haskell user isn't going to respond in
| any form about making side effects safer, because that's just one
| thing that they do...they're going to respond with other
| abstractions. And after 45 minutes of explanations of what they
| are, they still haven't yet gotten to the explanation of what you
| can do with it. And then when you finally understand what you can
| actually do with it, you have to confront the fact that they made
| an incredibly easy thing hard, just in case you might want to use
| it a different way.
|
| I cant recommend this rant enough -
| https://existentialtype.wordpress.com/2011/05/01/of-course-m....
| pyrale wrote:
| > * ML - includes SML, OCaml, F#, Scala, and Rust
|
| Scala and ocaml suffer from the same reputation. SML didn't
| really make it out of the academia. F# is easier, but still has
| a bad rap from C#ers. Rust is making incredible efforts to be
| accessible, but the learning curve is still steep.
|
| One could say haskell itself is also an offspring of the ML
| family.
|
| In that family, the article author correctly identified that
| Elm is probably among the most accessible. Choosing a specific
| application domain enabled the language creators to cut a lot
| of complexity, and to use a simple state machine as a runtime.
|
| > If you ask the question "what is a monad used for?"
|
| You'll get the same kind of answers as you'd get you'd get when
| asking Java programers what this "class" concept is about. The
| functor-applicative-monad stack is at the heart of Haskell's
| flavor of functional programming. You can write small programs
| without it, of course, but it's going to be the same experience
| as writing Java with a single "main" class.
| mrdoops wrote:
| Agreed. I would bet on a language like Elixir or F# being
| simpler to learn and grow for a complex system than a class-
| oriented-imperative-oop (Java, Ruby, Python, etc) language any
| day.
| JaggerJo wrote:
| +1
|
| We've been using F# with great success for a few projects now.
| Our stack is super simple.
|
| On the backend we use F# (on .NET with ASP.NET Core) +
| Postgres.
|
| On the frontend we use F# (via Fable with React and the Feliz
| Bindings).
|
| https://zaid-ajaj.github.io/Feliz/
|
| And we have a huge shared library. Works like a charm.
| [deleted]
| cutler wrote:
| I think learning functional programming is harder with a
| statically-typed language as there's so much more to learn which
| revolves solely around the type system. I would recommend anyone
| new to FP to try Clojure first. No mon[a|oi]ds necessary. I also
| think the transition from procedural languages is easier than
| from OO languages. I was lucky not to be exposed to Java or C++
| in the early days of my programming career, opting for Perl
| instead. When I transitioned to Ruby I also encountered Clojure
| at the same time and could appreciate the functional/lisp
| elements in the design of Ruby.
| stadium wrote:
| I had only one FP experience with scala. I actually liked that
| it was statically typed. I have nothing to compare it to
| though.
|
| But, higher order functions and type parameters are still a bit
| mind bending for me. I didn't have to write much code for
| those, but when I did it was really hard. I'm sure I'd need at
| least couple days of reading and playing around to somewhat
| grasp how to implement them again.
___________________________________________________________________
(page generated 2021-08-15 23:01 UTC)