[HN Gopher] Monads Schmonads: Functional Input Without Tears (PYFL)
       ___________________________________________________________________
        
       Monads Schmonads: Functional Input Without Tears (PYFL)
        
       Author : herodotus
       Score  : 22 points
       Date   : 2021-05-22 17:20 UTC (1 days ago)
        
 (HTM) web link (billwadge.wordpress.com)
 (TXT) w3m dump (billwadge.wordpress.com)
        
       | resoluteteeth wrote:
       | If you really want your program's output to be a pure function of
       | its input you can use the "interact" function in Haskell. I would
       | recommend that the author try this and see the limitations, since
       | it might help him start to understand why Haskell uses the IO
       | monad.
        
       | oisdk wrote:
       | [The original paper which introduced Monads to
       | Haskell](https://www.microsoft.com/en-us/research/wp-
       | content/uploads/...) is a fantastic read, and extremely easy to
       | understand. It explains clearly why monads are a good option, and
       | what problem they're meant to solve in Haskell.
       | 
       | In the article itself, the line:
       | 
       | > As it happens the computation will need the value of b before
       | that of a. If this is a problem, we can write the definition of
       | root1 as
       | 
       | Is actually quite interesting: the problem being described there
       | is almost _identical_ to one of the problems that Haskell had
       | with I /O, which motivated the introduction of monads.
        
       | sfvisser wrote:
       | Not entirely sure the author understands what problem monads
       | solve and how it relates to his examples.
       | 
       | If you just needs a fixed set of inputs without dependencies,
       | conditionals, branching etc you indeed don't need monads.
        
       | loa_in_ wrote:
       | Haskell uses monads to encompass IO actions because IO is so much
       | more than the stdout and stdin. The stderr, file operations,
       | accessing raw memory, network connections and all sorts of global
       | states are the domain of the IO monad.
        
       | garethrowlands wrote:
       | In the Haskell example in the article, the `do`, braces,
       | semicolon and `return ()` are not necessary:
       | main = do {   putStrLn "Hello, World!" ;   return ()   }
       | 
       | The code should read like this instead (and I think the linter
       | would suggest this):                   main = putStrLn "Hello,
       | World"
        
       | Blikkentrekker wrote:
       | From how I understand this approach, these are effectful
       | functions that have the size effect of printing on a prompt when
       | first ran.
       | 
       | While it is true that they yield the same result back to the
       | program on each invocation, so would _OCaml_ invocation
       | `Printf.printf  "Hello, World!"`, it namely always returns `()`,
       | but it is quite an effectful function, of course.
        
       | aranchelk wrote:
       | > Haskell uses the seriously complex machinery of monads to do
       | I/O, supposedly without side effects (I don't accept this).
       | 
       | The consensus of many highly intelligent people knowledgeable on
       | the subject seems to be monads allow you to maintain a pure
       | language while performing IO. This shouldn't make it an
       | incontestable fact, but probably should make disagreement worth
       | more than a throwaway line -- that is if you want to avoid
       | looking like a crackpot.
        
         | bade wrote:
         | I've proposed an approach that is simple, equation oriented and
         | trivial to implement. I think a substantive discussion off its
         | merits is more useful than arguing about consensuses.The
         | Haskell alternative is to write what are obviously commands in
         | what looks like C and I don't see this as pure. Sometimes the
         | emperor has no clothes.
        
         | goto11 wrote:
         | > monads allow you to maintain a pure language while performing
         | IO
         | 
         | I/O is by definition not pure, but the use of monads allow a
         | strict separation between the pure and impure parts of the
         | code. I guess you can say that monads allow you to have a
         | guaranteed pure sublanguage.
        
           | thewakalix wrote:
           | I'd say it's more that IO is a sublanguage. The type (Int ->
           | IO Int) seems more specialized than the type (Int -> Int),
           | for example.
        
           | aranchelk wrote:
           | Agreed, and AFAIK if you're implementing IO, it's either in
           | the runtime or you're doing FFI, so bizarrely (again AFAIK)
           | all of those statements are accurate.
           | 
           | Edit: sorry I glossed over the last bit regarding a sub-
           | language. The point is the whole language is considered (at
           | least by many of its proponents) pure: monads + runtime + FFI
           | are the gymnastics that allow one to perform IO in a pure
           | language.
        
         | Blikkentrekker wrote:
         | That's not a consensus at all.
         | 
         | Many are of the position that the IO monad is purely a type
         | theoretical hack that allows one to control the order of
         | effectful functions in _Haskell_ that under the surface creates
         | a vacuous data dependency that ensures the optimizer must
         | sequence them in a particular order.
         | 
         | There is no consensus as to what the IO monad "is"; only what
         | it's specific semantics with regard to execution order is.
         | 
         | But it serves it's purpose in that allows one to control the
         | order of certain effects in another wise non strict language
         | while semantically not necessarily relying on controlling the
         | order of execution of function calls.
         | 
         | On the type level, the effect of the function is separated from
         | the calling of the function and it's effect need not
         | necessarily take place conceptually when the function be
         | called; under the hood, it simply ensures that the optimizer
         | cannot move out of order the effectful kernel of the function
         | by way of this vacuous data dependency.
        
           | anderskaseorg wrote:
           | It's easy to demonstrate that the IO monad is pure by
           | reimplementing it in 100% pure code.                   {-#
           | LANGUAGE GADTs #-}              data IO' a where
           | Pure :: a -> IO' a           Bind :: IO' a -> (a -> IO' b) ->
           | IO' b           PutStrLn :: String -> IO' ()
           | GetLine :: IO' String           -- more IO operations...
           | instance Functor IO' where           fmap f ma = Bind ma
           | (Pure . f)              instance Applicative IO' where
           | pure = Pure           mf <*> ma = Bind mf (\f -> Bind ma
           | (Pure . f))              instance Monad IO' where
           | (>>=) = Bind
           | 
           | The actual implementation in GHC is much more efficient, of
           | course. GHC does all sorts of magic to hide the fact that
           | it's generating straight-line code instead of a tree-like
           | data structure full of continuation functions. But it's
           | semantically equivalent.
        
             | Twisol wrote:
             | You're right, but I think there's a distinction here that
             | is easy to miss.
             | 
             | An IO action _describes_ what to do, but something still
             | has to _do_ that action. A Haskell program on its own doesn
             | 't do anything; that's exactly why it's pure. The Haskell
             | runtime _interprets_ an IO value, unraveling it into the
             | string of commands that comprise it. The runtime executes
             | the commands produced by the Haskell program.
             | 
             | Haskell uses monads exactly because it lets you
             | describe/express complex sequences of actions (for which
             | later actions depend on earlier actions) _without_
             | requiring that the machinery for actually performing those
             | actions be part of the program too.
        
         | bitwize wrote:
         | Monads don't make side effects in I/O go away, but they do help
         | you manage them. Crucially, the IO monad _describes_ a
         | computation which must then be _run_. Computations are
         | describable in side-effect-free code. Running them is handled
         | automatically by the Haskell runtime, and can be done without
         | introducing side effects into the language.
        
       | vmchale wrote:
       | > Haskell uses the seriously complex machinery of monads to do
       | I/O, supposedly without side effects (I don't accept this).
       | 
       | Seems like the author doesn't understand what's going on.
        
         | tromp wrote:
         | > And you end up writing stuff like main = do { putStrLn
         | "Hello, World!" ; return () } which to me looks like C. There
         | must be a more functional approach.
         | 
         | It looks imperative because that's what Haskell's do-notation
         | was designed to. But it's merely syntactic sugar for the
         | functional equivalent                   main = putStrLn "Hello,
         | World!" >> return ()
         | 
         | which btw is equivalent to simply                   main =
         | putStrLn "Hello, World!"
        
       ___________________________________________________________________
       (page generated 2021-05-23 23:01 UTC)