Skip to content
DevMeme
5619 of 7590
Languages Post #6166 · source on Telegram

The Ultimate Customer Requirement: Haskell

Description

A screenshot of a tweet from the user 'chreke' (@therealchreke). The tweet, posted on April 18, 2024, presents a satirical 'uncomfortable truth'. The text reads: 'Uncomfortable truth: The customer doesn’t care about your “product”. They don’t care about your “solution”. The only thing they care about is whether it is written in Haskell or not'. The image has a clean, standard Twitter UI layout with black text on a white background. The humor is deeply ironic, playing on the well-known reality that customers are almost always completely indifferent to the underlying technology stack of a product. It satirizes the tendency of some developers, particularly those in niche communities like functional programming, to become so enamored with their chosen tools that they jokingly project their own priorities onto the end-user, creating an absurd scenario where a customer's primary concern is the use of a specific, academically-oriented language like Haskell

Comments

60
Anonymous ★ Top Pick Of course the customer cares if it's written in Haskell. How else would they know to file a bug report titled 'Unexpected lazy evaluation caused the heat death of the universe'?
  1. Anonymous ★ Top Pick

    Of course the customer cares if it's written in Haskell. How else would they know to file a bug report titled 'Unexpected lazy evaluation caused the heat death of the universe'?

  2. Anonymous

    Enterprise sales funnel these days: Lead → Demo → Realise it’s written in Haskell → Closed-Won - because nothing screams “low risk” like a monad stack with fourteen type parameters

  3. Anonymous

    After 20 years of explaining monads to stakeholders, I've finally realized the real monad was the friends we confused along the way - and they still just want their CSV exports to work

  4. Anonymous

    This perfectly captures the eternal struggle between engineers who want to rewrite everything in their favorite pure functional language and stakeholders who just want the damn feature shipped. Spoiler: The customer actually cares whether it works, scales, and doesn't bankrupt them in cloud costs - but sure, let's have another 3-hour architectural debate about monads and type safety while the competitor ships in Python

  5. Anonymous

    Enterprise RFP: “Must be scalable, secure, and written in Haskell” - translation: we’ll trade ROI for IO, but only if it typechecks

  6. Anonymous

    Pitch: “Haskell gives you compile-time guarantees.” Client: “Great - can you also give us compile-time candidates?”

  7. Anonymous

    Haskell: Where customers demand purity until their monadic business logic hits production impurity

  8. @sankyago 2y

    Uncomfortable truth: The customer doesn't care about your "product". They don't care about your "solution". The only thing they care about is whether it is written using microservices or not 🥺

  9. @VanuxaKR 2y

    Thia is so λx.λy.x

    1. @purplesyringa 2y

      This is so... "K"? What?

      1. @VanuxaKR 2y

        True This is so true

        1. @purplesyringa 2y

          ah

          1. @purplesyringa 2y

            I love untyped lambda calculus 😈

            1. @purplesyringa 2y

              can't stop obsessing over how 0 = [] = false holds both in JavaScript and lambda calculus

  10. @VanuxaKR 2y

    At least not in Rust

    1. @LonelyGayTiger 2y

      Rust is the Haskell of the future.

      1. @purplesyringa 2y

        Rust is not Haskell, at all

        1. @purplesyringa 2y

          maybe Idris, but not Rust, totally not Rust

    2. @Saeid025 2y

      Rust is haskell brother that is just a little less crazy

  11. @LonelyGayTiger 2y

    They're obviously very different languages, but Rust took a lot of inspiration from Haskell for the functional aspects of the language.

    1. @purplesyringa 2y

      I'm afraid I don't understand. Rust looks as far from functional programming as possible to me. I'd concede that it likely inherited typeclasses from Haskell, which certainly influenced some decisions, but it doesn't have monads and generally makes writing code in functional style quite unfriendly, exactly because it doesn't have monads

      1. @LonelyGayTiger 2y

        Doesnt have monads? The two most commonly used types in Rust are the Option and Result types. Both of which are monads.

        1. @purplesyringa 2y

          They might be monads by a formal definition, but they don't really compose like monads typically do. There's ? that kinda makes it look like Rust has do notation, but this illusion breaks down when you use iterators of results or something similar

          1. @purplesyringa 2y

            I should probably have said that Rust has monads but not the concept of a monad. There isn't even a generic return, much less a bind

          2. @LonelyGayTiger 2y

            Using iterators of either options or results is about as seamless as you could possibly want. Largely because they will seamlessly convert themselves into iterators.

            1. @purplesyringa 2y

              There's try_find, try_collect, try_for_each, try_reduce, and I think many more methods to come, because iterators and results simply don't compose unless std explicitly hacks that in

              1. @purplesyringa 2y

                Also, async functions are kinda monadic too, and yet they're their own beasts, different from every other monad in existence

                1. @purplesyringa 2y

                  Don't even get me started on async iterators...

              2. @LonelyGayTiger 2y

                I lack the explicit functional programing experience to understand exactly what you mean by compose in this context. But in most cases you'll just flatten, flat_map, or map them.

                1. @purplesyringa 2y

                  Say I have impl Iterator<Item = Result<T, E>> and I want to find the first T that satisfies a predicate, but also abort on first error. Imperatively, I want for result in iterator { let value = result?; if predicate(value) { return Ok(Some(value)); } } Ok(None) How do I implement this in functional style?

                  1. @LonelyGayTiger 2y

                    In that case you'd use the find_map function. It would definitely be a little awkward. let collection: Vec<Result<T, E>> = ... // For example let result: Option<Result<T, E>> = collection.into_iter().find_map(|result| match result { Ok(t) => { if t == value {Some(Ok(t))} else {None}}, Err(_) => Some(result) });

                    1. @purplesyringa 2y

                      oof

                      1. @purplesyringa 2y

                        Result<Option<T>, E> would probably be more idiomatic, but I see what you mean

                        1. @purplesyringa 2y

                          I just think that this would look a lot better in a language with first-class monad support

                          1. @LonelyGayTiger 2y

                            I'm certain there's probably a much better way to do this. I'm just away from my development machine currently and it's past midnight. Lol

                            1. @purplesyringa 2y

                              let result: Option<Result<T, E>> = collection.into_iter().find_map(|result| match result { Ok(t) if t != value => None, _ => Some(result) }); like this maybe. looks cringe though

                              1. @LonelyGayTiger 2y

                                I'm pretty sure that's not valid syntax. But it seems like you're on the right track. I'm going to ask some people who know better than I do.

                                1. @purplesyringa 2y

                                  fn try_find<T, E>( mut it: impl Iterator<Item = Result<T, E>>, mut predicate: impl FnMut(&T) -> bool, ) -> Option<Result<T, E>> { it.find_map(|result| match result { Ok(value) if !predicate(&value) => None, _ => Some(result), }) } this compiles https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=d06fa19e9590bbb9510ce3a9cabe6fe3

                              2. @Saeid025 2y

                                bro you are making it hard for yourself this can be way more simplified you can just use is_ok_and and then to simplify the code even more

                        2. @LonelyGayTiger 2y

                          It has to be the other way around because the input could be empty.

                          1. @purplesyringa 2y

                            That'd just be Ok(None), I suppose

                            1. @purplesyringa 2y

                              But I can just add a .transpose() to the mess; still not great implementation-wise though

      2. @Agent1378 2y

        Who cares about monads? Monoids in the endofunctor category is all we need!

  12. @kuybida_daniel 2y

    + diversity, inclusivity and equality

  13. @VanuxaKR 2y

    Damn, I love to create holy war in the chat 🍿😎

  14. @LonelyGayTiger 2y

    Ah, right, with the advanced pattern matching.

  15. @LonelyGayTiger 2y

    I dont actually play around with that much.

    1. @purplesyringa 2y

      I'd argue they just complicate the code in this particular case

      1. @LonelyGayTiger 2y

        Ah, There's a much simpler way to do this. collection.into_iter().find(|result| result.is_err() || result == Ok(value))

        1. @purplesyringa 2y

          I wanted a combinator that takes a predicate, not an expected value. So it'd be result.is_err() || predicate(result.as_ref().unwrap()) probably. A bit less simple

          1. @LonelyGayTiger 2y

            then replace result == Ok(value) with predicate(result.unwrap())

            1. @purplesyringa 2y

              Yeah. Still worse than a hypothetical magical monad combinator though

              1. @LonelyGayTiger 2y

                I think iter.find(|result| result.is_err() || predicate(result.unwrap())) is pretty ok all things considered. Very usable, and definitely cleaner than the loop based version.

                1. @purplesyringa 2y

                  Add an .as_ref(), but yeah, sure. That's honestly better than I imagined. Short-circuiting to the rescue

  16. @LonelyGayTiger 2y

    You could probably simplify it more by using matches!() instead of a match. But I'm not certain how exactly you'd convert that.

  17. @LonelyGayTiger 2y

    Though the Rust discord points out that in most cases if you end up with a collection of Results you probably made a poor decision about program structure earlier in your code.

    1. @purplesyringa 2y

      I don't have a collection of results, I have an iterator of results. Say, a directory iterator yielding Result<DirEnt>.

  18. @LonelyGayTiger 2y

    You could make it a lot cleaner too depending on how much flexibility you have for your predicate.

  19. @LonelyGayTiger 2y

    If the predicate accepted a result or an iterator instead of a single value then you could probably just do iter.find(predicate)

  20. @LonelyGayTiger 2y

    iterator is probably the way I'd go.

Use J and K for navigation