OOP is TRWTF



  • @djls45 said in OOP is TRWTF:

    @error said in OOP is TRWTF:

    @boomzilla said in OOP is TRWTF:

    @dkf said in OOP is TRWTF:

    @DogsB said in OOP is TRWTF:

    Reminds me of HashMaps in java. When you pull iterators out of them you can't guarantee the order of the items. Everywhere I've worked I've had to fix a bug related that.

    I'll take “what is LinkedHashMap and why would you care?” for 10, Bob.

    I think you misunderstood. I read his comment as similar to @blakeyrat's thing where DBs should return records in random order (at least some of the time) in the absence of an explicit ordering. Because some dev will see the order and make assumptions about it that come back to bite them.

    I seem to recall DirectX initializes newly allocated buffers with noise in debug mode but zeroes in release, to prevent similarly baseless assumptions.

    I think it was the other way around. Release tries to maximize efficiency, and always clearing new memory allocations can get expensive quickly. On the other side, debugging should have a clean environment between test runs, so zeroing the memory is helpful and the extra time required is an acceptable inefficiency.

    :trwtf: : Jokes on you, my code only works on Release mode! Debug mode is for wussies 🍹



  • @djls45 said in OOP is TRWTF:

    Well, obviously, you have to match the types. But can't you use monads to chain, say, an async read from a database, a nullable field access from the returned rows, and a lazy-evaluated operation on the fields?

    You would need to build a monad that can do all those actions. Monad transformers "stack" monads in the right way so that they compose how you describe. But, in general, you can't just mix and match.

    Actually, for some of the effects you mentioned, a monad does exist that can do them all -- IO. This is a part of why the IO monad in Haskell is a bit of a black eye. It's the async monad, the parallelism monad, the blah blah blah monad.

    Haskellers are looking for a solution to how to split the IO monad up into separate kinds of monads. But nothing has gathered enough community support to make such a big change. (They just did an important refactor on some core functionality for a "nice to have", so it's possible)



  • @Captain said in OOP is TRWTF:

    Actually, for some of the effects you mentioned, a monad does exist that can do them all -- IO.

    IO basically lets you do absolutely everything in runtime anyway. It further proves the point that monads are a Haskell thing.



  • I mean, monads are a math/logic/philosophy thing (first (very loosely) introduced by the Pythagoreans!). I was using them to interpret multi-world first order logic (S4) as a junior in like 2002.



  • @_P_ said in OOP is TRWTF:

    @djls45 Hold up there. I don't think you actually do.

    @djls45 said in OOP is TRWTF:

    F# calls monads "Computation Expressions", which you must agree is a far more useful and descriptive name than "monad."

    Calling it "Computation Expressions" would mean it's a very specific kind of monads in the context of continuation. Also even that's incorrect:

    Depending on the kind of computation expression, they can be thought of as a way to express monads, monoids, monad transformers, and applicative functors.

    So a monad IS-A computation expression.

    @djls45 said in OOP is TRWTF:

    a monad is an object that separates construction from evaluation by taking an input collection of some type in its constructor and providing a piece of code that takes that collection and a function, performs the function on the collection, then returns the resulting collection (which is most likely of a different type than the input) as the monad's output, which may be fed as the input into another monad.

    This allows chaining monads (one monad taking another monad as input, or in other words, nesting expressions), because each monad is essentially a node for a queue, pushing operations onto the head of the queue, and popping them off the tail and evaluating them as the output from preceding operations become available as inputs.

    Wat? :thonking: I think you're thinking too much about the bind operator.

    Huh? Given that it's one of the two required operations in the definition, how much consideration would you expect?

    What you described is a different, specific kind of "monad" usage, namely the collection/list. So it's one particular interpretation of the monad interface.

    Are you referring to the fact that my explanation talks about input and output collections, or that I described monads as a virtual queue?
    If the former, just replace every "input/output collection" with "input/output object or collection."
    If the latter, how is "virtual queue of operations" wrong?

    Before making interpretations of the monad interface, you need to understand how FP people work: they take things from category theory or first-order logic, translate it to a type signature via Curry-Howard correspondence, and then investigate if there are things in the wild that fits said type/pattern. From the beginning they don't care about what monad is; but rather "what kind of objects and operations fits this monad signature", so don't do meaningless jobs for them :trollface:

    I prefer to do useful work, and make programs that solve real-world problems, not make up fancy jargon so I can feel more erudite than those luddite imperative programmers. :trollface:

    (This reminds me of quantum mechanics and all those efforts of trying to interpret it. It's such a massive can of worms...)

    The explanation is pretty straightforward and simple: all energy and matter exists in tiny discrete units.
    The implications of what that means about the universe and how the universe operates are the difficult part.

    @djls45 said in OOP is TRWTF:

    It doesn't matter why the evaluation needs to be delayed, because the monad hides the boilerplate code to process the delay. The reason may be chaining access to nullable fields, chaining operations on collections that may vary in sizes, chaining asynchronous operations, or chaining sub-expressions into a closure in order to use a value later in the expression chain.

    There is a very big problem there: "monad"s doesn't do that for you, or magically. Monad is a interface.

    Well, yeah, that's what "hides the boilerplate code to process the delay" means.

    If you're writing a class, and you think your class can be made an implementation of monad, you need to provide an implementation for its two operations such that they obey the three laws/invariants. Then as an API user you look at the class and see, "hey, this class says it's a instance of monad, which means those 2 monadic operations are available and I can call them through the monad interface". Even if you don't make this class an implementation of monad interface these methods would still exist; they just aren't exposed through a ubiquitous Haskell interface (because again, monad is a Haskell meme). We can still live a good, happy life with that. You can also argue if monad is even a meaningful interface to begin with; for any languages that isn't Haskell, the answer is probably "no".

    It seems like it's a useful interface for any functional programming. (Hey, did you know that even parts of imperative languages can be "functional"? They're even called "functions"!)

    Also, async/await does not satisfy the requirement of being a monad because IIRC its bind operation is not associative. I suspect the author doesn't quite know what they're saying either.

    Of course. async/await aren't monads themselves, but they can be used with monads because of their delaying functionality. Using bind with asynchronous calls wouldn't make any difference than any other monadic uses, because the associativity is an attribute of the monad, not the bound function.

    @djls45 said in OOP is TRWTF:

    (Incidentally, I think this also helped me to understand closures, which was another concept that's been bugging me a bit.)

    Monad is but only one particular implementation of closures, so I think you're getting it backwards there. And I don't think anyone would, or had explained closures using monads, ever, because it really isn't helping.

    I don't think I'd use either one to explain the other, but it just so happened that this example finally made closures "click" for me.

    @djls45 said in OOP is TRWTF:

    ...Have I broken the "monad curse"?

    Nope, but if I have to give a suggestion, knowing what a monad is doesn't bring up anything useful either, so 🍹

    Are you sure I'm not just bad at explanations in general? Or is it that I'm just not explaining it your way? 🐠



  • @djls45 said in OOP is TRWTF:

    So a monad IS-A computation expression.

    A programmer IS-A human too. Would you explain to others what a programmer is by saying a programmer is a human? That's more uselessly :pendant: than I've been in this thread.

    @djls45 said in OOP is TRWTF:

    Huh? Given that it's one of the two required operations in the definition, how much consideration would you expect?

    Are you referring to the fact that my explanation talks about input and output collections, or that I described monads as a virtual queue?
    If the former, just replace every "input/output collection" with "input/output object or collection."
    If the latter, how is "virtual queue of operations" wrong?

    I said you're "thinking too much" as in that was an unnecessary over-interpretation on what the operator does. Excessive usage of interpretation and analogies hampers understanding because they're not capable of distinguishing different, similar concepts accurately. Next up if I ask you to explain Monoid, Arrow and their difference to Monad you'd either dodge the question, or make up more nonsensical analogies to keep the story going. I can already see that happening because it happens all the time.

    @djls45 said in OOP is TRWTF:

    I prefer to do useful work, and make programs that solve real-world problems, not make up fancy jargon so I can feel more erudite than those luddite imperative programmers.

    Well, then you don't really need to know what a monad is, you know 🚎 Curiosity is not a bad thing per se, but half-understanding is probably not.

    @djls45 said in OOP is TRWTF:

    The explanation is pretty straightforward and simple: all energy and matter exists in tiny discrete units.
    The implications of what that means about the universe and how the universe operates are the difficult part.

    Yes, and it's the exact problem in all the "monad tutorials" as far as I have seen: what most people (out of like 1% of the programmer populace anyway) need to know is really just how to utilize a monad others have implemented, which is as simple as "read the docs and don't write stupid stuff", or in QM terms, "shut up and calculate".

    Monad tutorials are, however, all kinds of analogies and interpretations that promises you an explanation to what is its nature. And my point is, there is no "nature", because not even the first people who conceived monad have that in mind anyway. If there is a "nature" it'd be, that ultimately the usage of monads boils down to a bunch of function compositions in a specific way, and it has some nice mathematical properties, and anything that can be used this way is a monad.

    @djls45 said in OOP is TRWTF:

    Of course. async/await aren't monads themselves, but they can be used with monads because of their delaying functionality. Using bind with asynchronous calls wouldn't make any difference than any other monadic uses, because the associativity is an attribute of the monad, not the bound function.

    It is a very important difference because bind is provided by monad itself, and hence part of the contract is that it absolutely should obey the invariants associated with it. If you don't and insist on calling the bind-like function bind, well, you can still pretend there is one, but anyone who uses them will be bitten by differences in results that shouldn't be as well as compiler optimizations, and proceed to call you :trwtf:.

    @djls45 said in OOP is TRWTF:

    I don't think I'd use either one to explain the other, but it just so happened that this example finally made closures "click" for me.

    Well, monads and closures are completely different things, but hey, if it works for you, then 🤷♂

    @djls45 said in OOP is TRWTF:

    Are you sure I'm not just bad at explanations in general? Or is it that I'm just not explaining it your way?

    See above



  • @boomzilla said in OOP is TRWTF:

    @_P_ said in OOP is TRWTF:

    I don't see how that's different from the typical Haskell-based monad tutorial:

    Whenever a normie looks at Haskell code he goes, ":wtf: is this line noise?!" And then he gets back to work.

    So it's just Perl then?



  • @djls45 If this is kinda, sorta, correct I think I implemented something very much like monads in a Java 1.4 project way back when.


  • ♿ (Parody)

    @Carnage said in OOP is TRWTF:

    @boomzilla said in OOP is TRWTF:

    @_P_ said in OOP is TRWTF:

    I don't see how that's different from the typical Haskell-based monad tutorial:

    Whenever a normie looks at Haskell code he goes, ":wtf: is this line noise?!" And then he gets back to work.

    So it's just Perl then?

    It's like Perl but without any of the punctuation stuff that's so important in Perl.



  • @_P_ said in OOP is TRWTF:

    A programmer IS-A human too.

    Is this a human????


  • Banned

    Okay so I have a question.

    Someone mentioned monad only being a design pattern. Someone else said that being a monad alone isn't useful for anything. And yet it's implemented as an interface.

    Why is it implemented as interface? Is there any point to it? Why would you ever want to abstract over the monad interface? In what scenario would you write a function that accepts any monad but only a monad, and not care whether it's a list or a future? Or is the monad interface a case of "never stopped to think whether they should"?


  • Discourse touched me in a no-no place

    @Gąska said in OOP is TRWTF:

    Why is it implemented as interface?

    Because there are things you can do with a monad that can be layered on top, and which therefore become applicable to a whole bunch of otherwise-disparate things.


  • Banned

    @dkf such as?


  • Discourse touched me in a no-no place

    @Gąska I don't know Haskell well enough to say for sure. 😘

    But I believe there's some deep connections with the theory of partial execution, termination-with-errors, etc.



  • @Gąska In what scenario would you write a function that accepts any monad but only a monad, and not care whether it's a list or a future?

    When you're passed a monad action as a value and you need to do things to it... in this context, the functions are called "combinators", because they're basically free theorems like the Lambda calculus' y combinator.

    Sometimes you care if a monad implements an interface, but don't particularly care which monad it is. So you'd write actions like:

    serveHome :: MonadServer m => m Html
    serveHome = do
       session <- getSession -- has type `m Session`
       processSession session
       handleUrl "/" $ do
          generateHtml
    

    (this is syntactically valid haskell, and I write code like it frequently, but I'm not targeting a real library here)



  • @dkf said in OOP is TRWTF:

    I don't know Haskell well enough

    Just from readingskimming this thread, I know too much about Haskell. I hardly know anything about it, but even that is more than I want to know.


  • Banned

    @Captain said in OOP is TRWTF:

    Sometimes you care if a monad implements an interface, but don't particularly care which monad it is. So you'd write actions like:

    serveHome :: MonadServer m => m Html
    serveHome = do
       session <- getSession -- has type `m Session`
       processSession session
       handleUrl "/" $ do
          generateHtml
    

    How's that any different from writing a function that returns simple unwrapped Html value, and using the specific monad's map equivalent to wrap it? It seems to me it would be the same amount of code, and not be any less generic - rather the opposite; it would be more generic because you could use it with things that aren't monads. And in this specific example, since it's not taking any value parameters, you could use a simple constant.



  • @Gąska Who wants to keep writing map equivalents? The Control.Monad version (liftM) is the generic map equivalent.

    Only functors have map anyway. And Functor is in the Monad class hierarchy.

    Your questions don't make any sense. I am consuming (fake) library code. So of course I'm going to use the interface that lets me do that.


  • Banned

    @Captain okay so let me ask a different way. If you removed all references to Monad and MonadServer from both serveHome and getSession, what could you not do with serveHome that you could do before, or what task would require more code than before?



  • serveHome wouldn't exist as a value that could generate Html after inspecting the session...



  • @_P_ said in OOP is TRWTF:

    @djls45 said in OOP is TRWTF:

    So a monad IS-A computation expression.

    A programmer IS-A human too. Would you explain to others what a programmer is by saying a programmer is a human? That's more uselessly :pendant: than I've been in this thread.

    It could certainly be part of it. Obviously, there would need to be more details given.

    @djls45 said in OOP is TRWTF:

    Huh? Given that it's one of the two required operations in the definition, how much consideration would you expect?

    Are you referring to the fact that my explanation talks about input and output collections, or that I described monads as a virtual queue?
    If the former, just replace every "input/output collection" with "input/output object or collection."
    If the latter, how is "virtual queue of operations" wrong?

    I said you're "thinking too much" as in that was an unnecessary over-interpretation on what the operator does. Excessive usage of interpretation and analogies hampers understanding because they're not capable of distinguishing different, similar concepts accurately.

    I've found that using a flawed analogy that someone understands and gets them 90% towards the concept is far better for teaching than using a perfect analogy that they don't understand at all.

    Next up if I ask you to explain Monoid, Arrow and their difference to Monad you'd either dodge the question, or make up more nonsensical analogies to keep the story going. I can already see that happening because it happens all the time.

    I don't know those terms, so I'd have to do some research to figure out what they are. If that's a dodge, so be it.

    In set theory, it looks like a monoid has the characteristics of having closure over a set (applying the function to any two values in the set produces a value in the set) and having an identity value (applying the function to the identity value in the set and another value from the set produces the other value—the identity value drops out). With fewer characteristics, it's a broader concept than a monad. I'm probably missing some details, but that's a good enough start for me, and I can refine it further whenever I have need of a better understanding of it.

    @djls45 said in OOP is TRWTF:

    The explanation is pretty straightforward and simple: all energy and matter exists in tiny discrete units.
    The implications of what that means about the universe and how the universe operates are the difficult part.

    Yes, and it's the exact problem in all the "monad tutorials" as far as I have seen: what most people (out of like 1% of the programmer populace anyway) need to know is really just how to utilize a monad others have implemented, which is as simple as "read the docs and don't write stupid stuff", or in QM terms, "shut up and calculate".

    Monad tutorials are, however, all kinds of analogies and interpretations that promises you an explanation to what is its nature. And my point is, there is no "nature", because not even the first people who conceived monad have that in mind anyway. If there is a "nature" it'd be, that ultimately the usage of monads boils down to a bunch of function compositions in a specific way, and it has some nice mathematical properties, and anything that can be used this way is a monad.

    You reject the Platonic idea that all monads contain a common character of "monad-ness"? 🎣

    I would think that understanding what a monad is or does would be of great use for any case that would be simplified or clarified or made more efficient by using monads. Only noticing after the fact that something happens to be a monad is pretty useless, and makes monads a useless concept to know.

    @djls45 said in OOP is TRWTF:

    Of course. async/await aren't monads themselves, but they can be used with monads because of their delaying functionality. Using bind with asynchronous calls wouldn't make any difference than any other monadic uses, because the associativity is an attribute of the monad, not the bound function.

    It is a very important difference because bind is provided by monad itself, and hence part of the contract is that it absolutely should obey the invariants associated with it. If you don't and insist on calling the bind-like function bind, well, you can still pretend there is one, but anyone who uses them will be bitten by differences in results that shouldn't be as well as compiler optimizations, and proceed to call you :trwtf:.

    I think you misunderstand me. I never said that bind would be asynchronous nor that it would violate the invariants. I said that the function passed as a parameter to bind can be asynchronous. The monad makes it so that the resulting return value of the asynchronous function call can be passed around whether the result is pending or actualized.



  • @djls45 said in OOP is TRWTF:

    In set theory, it looks like a monoid has the characteristics of having closure over a set (applying the function to any two values in the set produces a value in the set) and having an identity value (applying the function to the identity value in the set and another value from the set produces the other value—the identity value drops out). With fewer characteristics, it's a broader concept than a monad. I'm probably missing some details, but that's a good enough start for me, and I can refine it further whenever I have need of a better understanding of it.

    Closure operators actually satisfy the monad laws. (Oh but you meant something a little different than I usually mean when I say closure... so you were correct under that interpretation)

    A monoid IS more general, though. A monoid is a structure (like a group, algebra, ring, etc) where you can combine elements, and there is an identity element. Another name for a monoid is a semigroup. The category of strings is a monoid, since you can concat them and "" is in there.

    Monads are a kind of monoid where the combination amounts to stacking and joining layers.


  • Considered Harmful

    random musing: With all the 'prefer composition to inheritance' stuff I hear from the functional crowd, I wish there was a language that had both Kotlin's interface delegation (class Foo constructor(list: List<Bar>): List<Bar> by list // done!) and Dart's auto-interfaces (class Foo {} class Bar extends Foo {} class Baz implements Foo {} // no inheritance of Foo's internals!). You would be able to rewrite literally any object-oriented hierarchy with composition instead of inheritance with almost zero binary incompatibility.



  • @Captain said in OOP is TRWTF:

    Another name for a monoid is a semigroup.

    Well, why didn't you say that in the first place? Now everything is perfectly clear!

    Filed under: Clear as mud



  • @Gąska said in OOP is TRWTF:

    Okay so I have a question.

    Someone mentioned monad only being a design pattern. Someone else said that being a monad alone isn't useful for anything. And yet it's implemented as an interface.

    Why is it implemented as interface? Is there any point to it? Why would you ever want to abstract over the monad interface? In what scenario would you write a function that accepts any monad but only a monad, and not care whether it's a list or a future? Or is the monad interface a case of "never stopped to think whether they should"?

    There is a context to that: when the FP people designed stuff like functors, applicatives, arrows and monads, they were considering an abstract model of computation by composing structures at the level of category theory, which is essentially asking questions like "What kind of flow I can compose with functors only? Can I compose this flow with just functors, or do I need something stronger like an applicative?". Hence monad is not a pattern. It describes a structure with a certain power of composition (in monad's case, bind). It's more of something that describes how much power a particular type has to compose different structures.

    Now, onto the technical side, these things give you power to do different things, roughly in the order of their strength:

    • Functor describes the power to "lift" a function to map it over some structure, e.g mapping over a list
    • Applicative means besides the power of Functors, you can now lift pure values too, as well as performing applications (apply a function to a value) when both of them are over the structure. Which means now you can do function (a) {return [a];}
    • Monoid, aka "semigroup with an identity", provides you an associative binary operation and an identity element associated with it. e.g list concatenation with the empty list
    • Monad, besides the power of Applicative, also gives you the power to "unwrap" the structure. e.g concatmap/SelectMany/flat_map on a list. Note that without the power to unwrap lists, what you get would be list of lists of some values, and you can't turn it back to just a list of values.
    • Arrow is even more powerful, it has the full capability of a Monad and also allows you to do Applicative things that would otherwise be clumbersome/unproductive to do in Monads. Frankly I don't quite understand its actual power level either, so I'll just refer you to this instead

    Similarly, you can add more functionalities to these constructs: if you want to add an index to an Applicative, there's Step; if you want to add a boolean flag instead (e.g marking if the result is tainted or not), there's Flagged; so on and so forth.

    If you want to understand this line of thought and the eventual product, check out functor combinator pattern. Yes these types have weird names and all look so similar, but they mostly come from category theory, and you don't really need to memoize them; just remember what kind of structure you want over your flow and then choose the appropriate type. Monad is just one particular element in the entire zoo, it's really nothing important.


  • Considered Harmful

    @_P_ said in OOP is TRWTF:

    lift pure values

    @_P_ said in OOP is TRWTF:

    associative binary operation

    Remember that you are talking to the functional equivalent of mongoloids in the category of endofuckingidiots.


  • Banned

    @pie_flavor aren't you a college student? Associativity of operations should be still fresh in your mind. Or is American education really as bad as they say?



  • @pie_flavor said in OOP is TRWTF:

    @_P_ said in OOP is TRWTF:

    lift pure values

    @_P_ said in OOP is TRWTF:

    associative binary operation

    Remember that you are talking to the functional equivalent of mongoloids in the category of endofuckingidiots.

    I did said

    onto the technical side

    so my ass is covered :kneeling_warthog: 🍹



  • @pie_flavor said in OOP is TRWTF:

    @_P_ said in OOP is TRWTF:

    lift pure values

    Take an x and turn it into an f x or an m x or whatever. You "lift" x into the monad or functor or whatever.

    @_P_ said in OOP is TRWTF:

    associative binary operation

    "Binary operation": a function that takes two arguments and returns a value in the same type

    A binary operation * is associative when: (a * b) * c = a * (b * c)

    That is, it doesn't matter how you group the parentheses.

    Remember that you are talking to the functional equivalent of mongoloids in the category of endofuckingidiots.

    Hey, being genuinely curious is a good thing, no matter where you're starting.



  • @Gąska said in OOP is TRWTF:

    @pie_flavor aren't you a college student? Associativity of operations should be still fresh in your mind. Or is American education really as bad as they say?

    I think, by "the functional equivalent of mongoloids in the category of endofuckingidiots," he was referring to us, not himself.


  • Considered Harmful

    @HardwareGeek said in OOP is TRWTF:

    @Gąska said in OOP is TRWTF:

    @pie_flavor aren't you a college student? Associativity of operations should be still fresh in your mind. Or is American education really as bad as they say?

    I think, by "the functional equivalent of mongoloids in the category of endofuckingidiots," he was referring to us, not himself.

    :whynotboth:
    Huh, that's not an emoji yet. Paging @kazitor


  • Banned

    @Captain said in OOP is TRWTF:

    serveHome wouldn't exist as a value that could generate Html after inspecting the session...

    But why? If session wouldn't need a monad, neither would serveHome.



  • @Gąska People like writing imperative style code for imperative/container-like things, like servers.



  • @Gąska said in OOP is TRWTF:

    @Captain said in OOP is TRWTF:

    serveHome wouldn't exist as a value that could generate Html after inspecting the session...

    But why? If session wouldn't need a monad, neither would serveHome.

    session is only available as a plain value at where you bind getSession and the remaining part together. Otherwise it's m Session, and you can't treat it as a Session.

    @Captain said in OOP is TRWTF:

    @Gąska People like writing imperative style code for imperative/container-like things, like servers.

    I think one thing that answer didn't explain is that you need at least the power of Monad to write out while loops. An Applicative wouldn't cut it. Hence the use of Monad and not anything weaker or stronger.



  • @pie_flavor said in OOP is TRWTF:

    @_P_ said in OOP is TRWTF:

    lift pure values

    I.e. make an object or value of type T into an object of type Lifted<T>.

    @_P_ said in OOP is TRWTF:

    associative binary operation

    "Binary" refers to an operator op that takes two arguments a and b, which can be represented in various notations. The options are infix (a op b), prefix or Polish (op a b), or postfix or reverse-Polish (a b op). Math is usually infix, and function calls are usually prefix. Sometimes parentheses are placed around the arguments, either because the syntax of the language requires it or for grouping.

    "Associative" means (a op b) op c gives the same result as a op (b op c). In other words, grouping doesn't matter.

    "Commutative" means the order doesn't matter: a op b gives the same result as b op a.


  • BINNED

    @HardwareGeek said in OOP is TRWTF:

    @Captain said in OOP is TRWTF:

    Another name for a monoid is a semigroup.

    Well, why didn't you say that in the first place? Now everything is perfectly clear!

    Filed under: Clear as mud

    I found out about that myself once I looked it up, but I had that reaction non-sarcastically.
    Oh, it's just a semigroup. So, really, (like @_P_ keeps saying) it says almost nothing at all.


  • BINNED

    @_P_ said in OOP is TRWTF:

    • Functor describes the power to "lift" a function to map it over some structure, e.g mapping over a list
    • Applicative means besides the power of Functors, you can now lift pure values too, as well as performing applications (apply a function to a value) when both of them are over the structure. Which means now you can do function (a) {return [a];}

    What? So, given a function f(x), the Functor allows me to map over a list (i.e. F(f)([x,y,z]) = [f(x), f(y), f(z)]). And now the applicative allows me to "lift on pure values, too"? But couldn't my original function already do that? 😕

    • Arrow is even more powerful, it has the full capability of a Monad and also allows you to do Applicative things that would otherwise be clumbersome/unproductive to do in Monads. Frankly I don't quite understand its actual power level either, so I'll just refer you to this instead

    https://www.youtube.com/watch?v=9Nxbz3zlkjY


  • Discourse touched me in a no-no place

    @topspin said in OOP is TRWTF:

    Functor

    Basically, the Functor concept is of a function that takes a function as an argument. It's where math ceases to be First Order and becomes definitely formally intractable, and is not a big deal to programming which has been passing functions around for a long time.



  • @dkf said in OOP is TRWTF:

    Basically, the Functor concept is of a function that takes a function as an argument.

    I thought that that was a "higher-order function", and a "functor" was a closure. 😕



  • @topspin Applicative does a different kind of "threading" through.

    Suppose you have a function that takes 3 arguments (the :: means "has type"):

     myFunc :: a -> b -> c
    

    and suppose you have 3 actions like...

      sourceA :: m a
      sourceA = do
        stream <- openSocket port 
        parseStream stream
    
      sourceB :: m b
      SourceB = do etc
      sourceC :: m c
    

    You can't just apply myFunc to sourceA and sourceB and sourceC as is. You can rely on the monad interface, to do binding like:

    myResult = do
      a <- sourceA
      b <- sourceB
      c <- sourceC
    
      return (myFunc a b c)
    

    If m is applicative, then you can do:

     myResult =  myFunc <$> sourceA
                        <*> sourceB
                        <*> sourceC
    

    where <$> is the same as fmap (i.e., the mapping function). This syntax was chosen in analogy to how $ is function application in Haskell, and because it makes the Applicative notation nice to read.

    <*> is from the Applicative class. If I recall correctly, (<*>) :: Applicative f => f (a -> b) -> f a -> f b.

    Applicatives are strictly less flexible than monads (monads let you do logic that depends on a, b and c, for example), but they're nice to use and most people like them.


  • ♿ (Parody)

    @Captain said in OOP is TRWTF:

    @topspin Applicative does a different kind of "threading" through.

    Suppose you have...

    82758718-d3fc-4bcc-9fff-f5015835dcdb-image.png




  • ♿ (Parody)

    More seriously, I got lost right here:

    @Captain said in OOP is TRWTF:

    @topspin Applicative does a different kind of "threading" through.

    Suppose you have a function that takes 3 arguments (the :: means "has type"):

     myFunc :: a -> b -> c
    

    Saying :: means "has type" and then showing that makes no sense to me. Sorry, I know I'm just repeating my thing about how Haskell syntax is opaque to me.

    and suppose you have 3 actions like...

      sourceA :: m a 
      sourceB :: m b
      sourceC :: m c
    

    I don't see what's "active" about any of that. This is what I was talking about when I said that I couldn't figure out where the code was. I guess this is maybe just a prototype, like you'd find in a C header, but it still doesn't make sense to me.

    Jeez, even math math uses parenthesis for functions!



  • @boomzilla Yes, you're right. For example, sourceA might be something along the lines of...

    sourceA :: Network String
    sourceA = do
      stream <- openPort 80 
      return (parseStream stream)
    

    where openPort and parseStream are from a (fake) library.

    I wasn't particularly caring about how the sources built up their values for my Applicative example, though.



  • @boomzilla Those "3 actions" are "typedefs". The myFunc example is weird because it has multiple returns, because of Haskell's bizarre fetish for "currying" (transforming functions with multiple arguments into chains of lambdas that each take a single argument). It could be more legibly read as myFunc :: a, b -> c, but that's not The Haskell Way ™.


  • ♿ (Parody)

    @Captain that can't possibly be correct. How did those parentheses sneak in?! 🏆



  • @boomzilla I chose not to use $ to be easy on you. :-)

    sourceA :: Network String
    sourceA = do
      stream <- openPort 80 
      return $ parseStream stream


  • @Mason_Wheeler No, @boomzilla was right. I was just skipping the value definitions because I didn't care about them.


  • Discourse touched me in a no-no place

    @Captain I'm curious what $ gains in this case; it's the same number of characters either way because parens can sit tighter to the code.



  • @Captain OK, my mistake.

    Currying is still :crazy: though.


Log in to reply