OOP is TRWTF



  • @topspin said in OOP is TRWTF:

    I have a feeling that "assuming you're in the IO monad" is easier for almost everybody, after all. Because you have to do exactly nothing to do that.

    You already don't have to do anything to use a pre-defined monad. You just type in a differently named programming language with the same syntax.

    And you GET to not have to keep track all the stateful variables defined by your program, unless you are literally in a part of the computation that accesses the state, which is TAGGED by the computation's type.

    It's a monad is just a new kind of type that represents an embedded language.


  • Discourse touched me in a no-no place

    @boomzilla said in OOP is TRWTF:

    @Captain every so often I try to figure out what this monad shit is about and then I'm hit with a bunch of Haskell notation and I give up. I guess I'm too :belt_onion: to wrap my mind around the syntactical paradigms or something. And it's usually after some functional hipster is telling me about all these problems I have that I never really noticed as such before.

    +1.

    Also monad sounds too much like gonad to take seriously.


  • Discourse touched me in a no-no place

    @mott555 said in OOP is TRWTF:

    I feel like I just read something about cricket.

    At least cricket has funny sounding jargon. The only funny sounding thing about Haskell is doing everything in the IO gonad.


  • ♿ (Parody)

    @Captain said in OOP is TRWTF:

    especially if you don't know Haskell

    Whenever I look at some Haskell code, I end up wondering where the code is. Like I said, haven't invested the time (and honestly don't have a good enough reason to make me do so) to get used to the way it's all put together.



  • @dkf I dunno, it sounds kind of funny to call someone an endofunctor



  • If I only use static functions and pass structs around, am I doing OOP or not?


  • Discourse touched me in a no-no place

    Oh, another fun point is that the author apparently believes that it is impossible to have both FP and OOP in the same language. That's very much not true, though the most popular FP languages have tended to not support OOP. All you do in OO-FP is provide a way (plus relevant syntactic sugar) to easily delegate the selection of the concrete implementation function, while constraining the profile of what such calls can be done to some sort of interface profile. In short, if all objects/classes in the language are immutable (ignoring IO gonad shenanigans) and everything is designed to work by returning a different object, then the language is both FP and OOP.

    Dumbfuck Moronovich hasn't displayed the mental capacity to encourage me to believe he is able get why that might be so.


  • Banned

    @Captain nothing you say makes much sense to me, and neither does myriad of tutorials. But I've read enough of them today that I think I'm about to crack it, but I need an answer to one more question.

    Is there any difference between the IO monad in Haskell and a regular function that takes a tuple of the actual argument and some special state value, returning a tuple of the actual result and another special state value? If so, what is that difference?


  • Banned

    @dkf said in OOP is TRWTF:

    though the most popular FP languages have tended to not support OOP.

    Literally the two most popular FP languages are Scala and F#. And both are very much object oriented. I suspect it's the very reason why they're most popular (together with pre-existing ecosystem, of course, but it wouldn't be much help if they weren't object oriented).


  • Banned

    @Zenith said in OOP is TRWTF:

    If I only use static functions and pass structs around, am I doing OOP or not?

    Stuck with C?



  • @Gąska said in OOP is TRWTF:

    Is there any difference between the IO monad in Haskell and a regular function that takes a tuple of the actual argument and some special state value, returning a tuple of the actual result and another special state value? If so, what is that difference?

    Your intuition is absolutely correct, and that's how the IO monad used to be implemented in GHC (basically, the current reference haskell compiler). A monad attaches "context" (like the RealWorld state object) to a value. The combinators handle passing the hidden argument around, so you don't have to. The monad laws (the tricky math part) are a way of expressing properties an imperative language needs.

    My understanding is that the IO monad isn't implemented in this way anymore. But that's a long story and not really relevant right now.


  • Banned

    @Captain okay, but if the argument is hidden, how can a function access anything in the monad?


  • Discourse touched me in a no-no place

    @Gąska Option 1: It doesn't. That's OK. The bits you needed from the monad are ordinary values.
    Option 2: It does actually need the monad itself, and then it gets handed the monad explicitly.


  • ♿ (Parody)

    When reading this...

    ...I might as well be reading this:



  • @Gąska said in OOP is TRWTF:

    @Captain okay, but if the argument is hidden, how can a function access anything in the monad?

    So, there are two ways to interpret your question.

    1. What is Haskell's execution model?
    2. How do you reason about how monads and functions interact?

    I'll focus on 2. (It is true that Haskell's main is an IO action, so ultimately, IO will drive every computation in your program.)

    Say you want to know the current time. So you load up your interaction Haskell session and type

    getCurrentTime
    > 2011-21-33 00:00:00.0000
    

    getCurrentTime goes to the clock, and gets the DateTime. Then it passes it to the caller (the interactive system) which prints it.

    Now, say you really don't care what the date is, and you JUST want the time. You have a few options. Assuming you have a function named formatter which can format the date time into a time (so it has the type

    formatter :: DateTime -> Time
    

    you could type in, for example,

    getCurrentTime >>= (return . formatter)
    

    The 'return' injects the value back into the monad for you. In this way, you can use "generic" functions "in" your monad.

    Another option is to just have a "monadic" formatter, which might look like:

    formatterM :: DateTime -> IO Time
    formatterM = ...
    

    But if you go that route, you can call arbitrary IO actions (like launchTheMissiles) in your definition of a formatter. That may or may not make sense. As a general rule, it makes sense not to say something needs to use IO unless it actually does.

    But if you did it this way, you could do:

    getCurrentTime >>= formatterM
    

    or

    do
      t <- getCurrentTime
      formatterM t
    

    This is called do notation, and it's syntactic sugar for nested (>>='s)


  • BINNED

    @boomzilla said in OOP is TRWTF:

    When reading this...

    ...I might as well be reading this:

    I’ve read two paragraphs before realizing that it’s just Markov chain generated nonsense.

    Filed under: and then I clicked the second link.


  • Banned

    @Captain said in OOP is TRWTF:

    getCurrentTime
    > 2011-21-33 00:00:00.0000
    

    This raises so many questions.

    • What is the type of getCurrentTime?
    • Where exactly does getCurrentTime get current time from?
    • How do I write my own getCurrentTime?
    • Can I pass an alternative monad context or whatever it's called and make the getCurrentTime in standard library return something else than current time?
    • Since IO is a type constructor, I suspect I can have IO IO Time too. Is such a construct ever useful?

    @Captain said in OOP is TRWTF:

    Now, say you really don't care what the date is, and you JUST want the time. You have a few options. Assuming you have a function named formatter which can format the date time into a time (so it has the type

    formatter :: DateTime -> Time
    

    you could type in, for example,

    getCurrentTime >>= (return . formatter)
    
    • What is the type of return? Where is it defined? Can I substitute it for something else?
    • What's . and where does it come from?
    • Since do is syntax sugar for >>= chains, and I can chain >>= pretty much indefinitely, does it mean I can have multiple returns in a single do block and they all execute one after another? If so, what are the semantics of such construct - what does it mean to return multiple times in a do block?

    Another option is to just have a "monadic" formatter, which might look like:

    formatterM :: DateTime -> IO Time
    formatterM = ...
    

    But if you go that route, you can call arbitrary IO actions (like launchTheMissiles) in your definition of a formatter.

    Aren't monads supposed to prevent exactly that? Reduce the environment to the bare minimum that makes sense so the code can't do anything stupid?



  • @Gąska said in OOP is TRWTF:

    @Captain said in OOP is TRWTF:

    getCurrentTime
    > 2011-21-33 00:00:00.0000
    

    This raises so many questions.

    • What is the type of getCurrentTime?

    IO DateTime

    • Where exactly does getCurrentTime get current time from?

    Uses system library to get the time from the clock

    • How do I write my own getCurrentTime?

    Complicated. Haskell has a foreign function interface (which lives in IO) which you can use to literally interact with physical devices, etc.

    • Can I pass an alternative monad context or whatever it's called and make the getCurrentTime in standard library return something else than current time?

    This sort of thing is possible in theory, but only when a function is defined for arbitrary monads. For example, sequence :: (Monad m) => [m a] -> ma takes a sequence of actions and runs them in turn, whether m is IO, Maybe, State, etc.

    • Since IO is a type constructor, I suspect I can have IO IO Time too. Is such a construct ever useful?

    Yes. At the very least, you can pull the inner (IO Time) out of the outer IO and run it (or not!) So monads are something of a flow-control construct too.

    @Captain said in OOP is TRWTF:

    Now, say you really don't care what the date is, and you JUST want the time. You have a few options. Assuming you have a function named formatter which can format the date time into a time (so it has the type

    formatter :: DateTime -> Time
    

    you could type in, for example,

    getCurrentTime >>= (return . formatter)
    
    • What is the type of return? Where is it defined? Can I substitute it for something else?

    return has the type Monad m => return :: a -> m a (so it works with every monad). It's defined in a module called Control.Monad, in the Monad type class definition. If you were to define a monad of your own, you'd need to implement any two out of: join, return, and (>>=).

    Now, your question about "can I substitute it"?: it depends.

    • What's . and where does it come from?

    Function composition. Given functions f :: a -> b and g :: b -> c, g . f has the type g . f :: a -> c

    • Since do is syntax sugar for >>= chains, and I can chain >>= pretty much indefinitely, does it mean I can have multiple returns in a single do block and they all execute one after another?

    Yes.

    If so, what are the semantics of such construct - what does it mean to return multiple times in a do block?

    It doesn't break.

    Another option is to just have a "monadic" formatter, which might look like:

    formatterM :: DateTime -> IO Time
    formatterM = ...
    

    But if you go that route, you can call arbitrary IO actions (like launchTheMissiles) in your definition of a formatter.

    Aren't monads supposed to prevent exactly that? Reduce the environment to the bare minimum that makes sense so the code can't do anything stupid?

    Yes.

    Haskell's IO monad has become a bit of a "sin bin", since it handles C libraries, printing, and a bunch of other things, basically through the same raw system interfaces. See some (well-known Haskell person) talking about this issue here: https://mail.haskell.org/pipermail/haskell-cafe/2008-September/047069.html

    If you're serious about security and need to use IO, you wrap into your own monad or similar.


  • Banned

    @Captain aha! So IO monad really is a thinly disguised escape hatch to impure code!



  • @Gąska It's not even disguised. It's literally named.

    And like I said, main is in the IO monad. Impure code (the runtime system, your OS) literally runs your impure and pure code.

    If you were just trying to make a point, you could have saved us both some time. ;-)


  • ♿ (Parody)

    @Gąska said in OOP is TRWTF:

    @Captain aha! So IO monad really is a thinly disguised escape hatch to impure code!

    That's literally the only fact about monads that I'm clear on, and have been for a long time.


  • Banned

    @Captain but all Haskell programmers are so bent on IO monad being absolutely pure construct and not a dirty hack at all, talking some bullshit about controlling side effects and whatnot. If they were honest and just said "the IO monad is the reverse of Fortran's PURE keyword - it marks a specific function as impure so it can do all the impure stuff that every other language can do by default", it would go a very long way to make Haskell more accessible to programmers.



  • @Gąska Sounds made up.

    In fact, you have to load up compiler extension to write Foreign Function interface code, so it is not the normal situation unless you are writing library bindings.

    Plus, IO isn't the only monad. There's State, Maybe, the list, and a ton of other monads. Many of which are made to control side-effects. None of which are escape hatches to anywhere, and run nothing but pure haskell code.

    In fact, my point through out this whole thread was 1. in agreement, that we can and should specially mark impure computation, and 2, if we have the machinery to do that, we can mark all the other kinds of computation.


  • Banned

    @Captain said in OOP is TRWTF:

    If you were just trying to make a point, you could have saved us both some time. ;-)

    I was trying to understand what the hell monads are. Because I was under false impression that there's something more to IO monad than just sticking the equivalent of JavaScript's window object to some value to give uncontrolled access to everything that goes against the spirit of functional programming to every function it passes by. Now that you've explained it's just fancy syntax around passing window around, everything makes sense.

    @Captain said in OOP is TRWTF:

    Sounds made up.

    If I made that up, how come there are so many very talented programmers that struggle with such a simple concept as that IO monad is just a wrapper for a collection of C functions that can do with the computer everything that Haskell itself can't? And why it's never explained in any Haskell tutorial in the entire internet?

    Plus, IO isn't the only monad.

    But it's the only one that allows for impure code (if we consider the monad object itself an argument to a function, which it absolutely is).



  • @Gąska said in OOP is TRWTF:

    If I made that up, how come there are so many very talented programmers that struggle with such a simple concept as that IO monad is just a wrapper for a collection of C functions that can do with the computer everything that Haskell itself can't? And why it's never explained in any Haskell tutorial in the entire internet?

    Because the hack is the Foreign Function Interface, which isn't normally used except for writing library bindings.

    IO doesn't exist to do FFI. FFI exists in IO because it does IO.


  • Banned

    @Captain I'm not talking just about FFI. I'm also talking about printing to stdout, about getCurrentTime, and about everything else that makes Haskell code dependent on the outside environment beyond what's explicitly listed in types of arguments.



  • @Gąska It's right there in the name. Input Output.


  • Banned

    @Captain yeah but what's not in the name is The Following Code Is Impure And Don't Even Try Pretending Otherwise. Which wouldn't be that bad, if Haskell programmers didn't pretend otherwise.



  • @Gąska Except it's all interpreted. The Haskell code is not the code it calls.


  • Banned

    @Captain what does that even mean. How's Haskell different from Python in that regard? Python is definitely interpreted, and definitely not pure at all.



  • It's not. You wouldn't say 'put' is an ESCAPE HATCH ZOMG!!!!

    It's a python function that gets interpreted, and the interpreter interprets it, and calls system functions on its behalf.

    Note that I told you all this in our second post.

    I'll focus on 2. (It is true that Haskell's main is an IO action, so ultimately, IO will drive every computation in your program.)


  • Banned

    @Captain said in OOP is TRWTF:

    It's not. You wouldn't say 'put' is an ESCAPE HATCH ZOMG!!!!

    I wouldn't because there's nothing to escape from in Python. It's impure by default. As opposed to Haskell, which is pure by default. And so it needs an impure escape hatch of some sort if it ever wants to do anything interesting (ie. observable from outside). And it's fine to have such escape hatch. What's not fine is the zealots who cannot let themselves admit that their beloved perfectly pure functional language isn't as perfectly pure as they think, and invoke theorems from PhD-level mathematics just to obscure that fact. IO monad exists to cause side effects. Functions that take IO monad use it to cause side effects. Functions that take IO monad are therefore impure.

    It's a python function that gets interpreted, and the interpreter interprets it, and calls system functions on its behalf.

    OK, and? Interpreting those functions causes side effects. It's because the functions prescribe those side effects to happen. They're impure functions even if there is no interpreter.

    What's your point anymore? What are you even trying to show with that split between what the code causes the interpreter to do and what the interpreter does when it sees the code?



  • @Gąska What the hell is your point?

    I don't need the lecture. You said you were interested and I helped.

    I already know exactly how pure Haskell is. And I know what the point of monads is.

    So what the hell is your point?

    They're impure functions even if there is no interpreter.

    You're splitting hairs with someone who already knows all this and getting it wrong. Hint: Aside from IO, every single monad is definable using pure Haskell code, and even IO used to be defined in pure Haskell code and interpreted by the runtime system.

    SO WHAT IS YOUR POINT?


  • ♿ (Parody)

    @Captain said in OOP is TRWTF:

    What the hell is your point?

    He's confused and taking it out on you.

    You're splitting hairs with someone who already knows all this and getting it wrong.

    YMBNH


  • Considered Harmful

    @Captain said in OOP is TRWTF:

    @boomzilla: yeah, a "monad" as a general concept have exactly the same complexity as an "imperative programming language". Haskell is powerful enough to let you design your own imperative programming languages (typically to deal with an effectful computation).

    So what do you need to define an imperative language? Syntax, and semantics for passing values around. The "hard" part of the Haskell tutorials (especially if you don't know Haskell) is seeing the forest for the trees, and realizing that they are using Haskell notation to:

    1. name the imperative language (Maybe, IO, the type variable m, etc)
    2. defining the semantics of taking values out of value with type m a and passing them into a function that that takes in an a and returns an m b (which guarantees that we stay "in" the monad)

    If you get those two ideas, and how 2 lets you define chains of computations by "pulling values" from expressions, then you're 100% of the way there. If you do both of these, you can treat the language defined by m as an imperative programming language in its own right.

    And similarly to imperative languages and their libraries, you don't need to know how to write a library (or a monad) to use one.

    You're not making your case that it's easy.



  • @pie_flavor But if you understand imperative programming, you sort of understand using different languages for different purposes. ;-)


  • Banned

    @Captain said in OOP is TRWTF:

    @Gąska What the hell is your point?

    That it's true that Haskell programmers lie about functions using IO monad being pure, that code has semantics even if it wasn't pushed through interpreter yet, and that I'm completely lost on what you're saying and why.

    You said you were interested and I helped.

    Yes you did. And I'm glad you did. But now you're doing something that I cannot even find words to describe, and I just can't understand why you do this.

    FAKE EDIT IN RESPONSE TO YOUR REAL EDIT:

    You're splitting hairs with someone who already knows all this and getting it wrong.

    SO WHAT IS YOUR POINT?

    Right now? Well, since you said I've got it wrong, I'd like to know what's wrong with what I said. You disagree that code has semantics without interpreter? You disagree that a function whose code prescribes side effects is impure?

    FAKE EDIT #2 IN RESPONSE TO YOUR REAL EDIT #2:

    Hint: Aside from IO, every single monad is pure definable using pure Haskell code, and even IO used to be defined in pure Haskell code and interpreted by the runtime system.

    Technically, you can define the entire C++ standard library with pure functions alone. They won't do what you ask them for, but they'll be pure!


  • Considered Harmful

    @Captain said in OOP is TRWTF:

    @Gąska said in OOP is TRWTF:

    @Captain okay, but if the argument is hidden, how can a function access anything in the monad?

    So, there are two ways to interpret your question.

    1. What is Haskell's execution model?
    2. How do you reason about how monads and functions interact?

    I'll focus on 2. (It is true that Haskell's main is an IO action, so ultimately, IO will drive every computation in your program.)

    Say you want to know the current time. So you load up your interaction Haskell session and type

    getCurrentTime
    > 2011-21-33 00:00:00.0000
    

    getCurrentTime goes to the clock, and gets the DateTime. Then it passes it to the caller (the interactive system) which prints it.

    Now, say you really don't care what the date is, and you JUST want the time. You have a few options. Assuming you have a function named formatter which can format the date time into a time (so it has the type

    formatter :: DateTime -> Time
    

    you could type in, for example,

    getCurrentTime >>= (return . formatter)
    

    The 'return' injects the value back into the monad for you. In this way, you can use "generic" functions "in" your monad.

    Another option is to just have a "monadic" formatter, which might look like:

    formatterM :: DateTime -> IO Time
    formatterM = ...
    

    But if you go that route, you can call arbitrary IO actions (like launchTheMissiles) in your definition of a formatter. That may or may not make sense. As a general rule, it makes sense not to say something needs to use IO unless it actually does.

    But if you did it this way, you could do:

    getCurrentTime >>= formatterM
    

    or

    do
      t <- getCurrentTime
      formatterM t
    

    This is called do notation, and it's syntactic sugar for nested (>>='s)

    You're still not helping


  • ♿ (Parody)

    @Captain said in OOP is TRWTF:

    @pie_flavor But if you understand imperative programming, you sort of understand using different languages for different purposes. ;-)

    I strongly suspect that if someone made Haskell but with more C-like syntax all this argle bargle wouldn't be necessary (but at the same time I'm sure it would lose a lot of its appeal with a certain type of Haskell enthusiast). Maybe if I'd encountered it closer to college when I was more used to reading math I'd be more interested in figuring it out as-is.



  • @boomzilla Yeah, I mean, monads are definitely abstract, and probably new idea to most programmers. Plus there's the difficulty of expressing an abstract idea in a language that is foreign to most programmers.

    There are some C# tutorials on Monads...



  • So, let's see if I get it right.

    • The concept of GMonads is super general, which is why everybody totally fails at explaining them.

    • The example that Wikipedia has, the Maybe monad, is just a bunch of fancy wrappers around an optional thing. If it's engaged, you do stuff to it, and if it's unengaged, you just forward that state.

    • The IO monad is a basically a thing that you pass around that sequences "IO" operations. It does that by pretending that there is some state. The fact that it's a monad just hides the virtual state that's passed around under the monad interface.

    You could implement something like that in other programming languages. Some actually do that for their optionals. You could do it for IO, if you wanted to make the sequencing more explicit, but for imperative languages that's mostly unnecessary.



  • @Gąska said in OOP is TRWTF:

    That it's true that Haskell programmers lie about functions using IO monad being pure, that code has semantics even if it wasn't pushed through interpreter yet, and that I'm completely lost on what you're saying and why.

    Every monad is pure computation in a (potentially) impure context.

    Every monad is interpreted in an environment.

    Every monad is (at least able to be written) as pure Haskell. Even the parts of IO defined by the Haskell standard.

    A monk writes on a sheet of paper:

    Go to a bordell and do filthy things with the prostitutes there.
    

    Can you accuse the monk of adultery?


  • Banned

    @Captain said in OOP is TRWTF:

    @Gąska said in OOP is TRWTF:

    That it's true that Haskell programmers lie about functions using IO monad being pure, that code has semantics even if it wasn't pushed through interpreter yet, and that I'm completely lost on what you're saying and why.

    Every monad is pure computation in a (potentially) impure context.

    And every function that interacts with an impure context in impure way is impure. Even if it hasn't been executed yet. It's not purity of monads that's important, it's purity of functions (important not as in every function should ideally be pure; important as in it's useful to classify functions as pure or impure, as it has practical implications.)

    A monk writes on a sheet of paper:

    Go to a bordell and do filthy things with the prostitutes there.
    

    Can you accuse the monk of adultery?

    A function isn't the monk. A function is the sheet of paper. And that sheet of paper absolutely does prescribe adultery. Even if no one followed the instructions yet. When that Ingo guy said "[this] expression is pure", he was wrong. It's not. It causes side effects when executed. It's meant to cause side effects when executed. Purity of >>= and return is irrelevant.


  • ♿ (Parody)

    @Captain said in OOP is TRWTF:

    Yeah, I mean, monads are definitely abstract, and probably new idea to most programmers. Plus there's the difficulty of expressing an abstract idea in a language that is foreign to most programmers.

    True. But also it's a fancy name for stuff you do with imperative programming all the time and don't think about it, even if it's not as elegant as the fluent code is. But with the fancy laws to make FPers feel special.



  • @topspin said in OOP is TRWTF:

    Filed under: and then I clicked the second link.

    Are you sure you're German?



  • @Gąska said in OOP is TRWTF:

    A function isn't the monk. A function is the sheet of paper. And that sheet of paper absolutely does prescribe adultery. Even if no one followed the instructions yet. When that Ingo guy said "[this] expression is pure", he was wrong. It's not. It causes side effects when executed. It's meant to cause side effects when executed. Purity of >>= and return is irrelevant.

    No, you're wrong.

    Haskell is defined in a certain way. Haskell expressions are evaluated, and the only thing that executes is the runtime system which builds a tree of computations out of main (i.e. it evaluates them and then executes the compiled code). Every time you pass around some IO action foo, you are passing around the same IO action (so that you have referential transparency).

    By definition, you are wrong. No amount of hand-wringing is going to change the definition. You may as well yell about irregardless begging the question.

    You're welcome.


  • Considered Harmful

    I finally understand monads, and a good monad tutorial is 'just go read the Stream#flatMap or Option#flatMap documentation' AFAICT.


  • Considered Harmful

    @Captain I also get this now too. You're explaining it wrong, as though you were talking to a functional person instead of an object-oriented person.
    Better explanation: all functions can be inlined, and indeed doing anything other than inlining at the call site is an implementation detail. Therefore 'local state in main' and 'mutable external state' can be treated as the same thing, because they effectively are the same thing.


  • Considered Harmful

    I read this thread and all I got was this lousy headache.


  • Considered Harmful

    @powerlord said in OOP is TRWTF:

    @Dragoon My favorite part of this article by far is the part where he calls multi-threaded code bad.

    That's where there's more than just a grain of truth in his criticisms.


Log in to reply