Advertisement
Guest User

Untitled

a guest
Jan 29th, 2020
93
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.85 KB | None | 0 0
  1. Haskell is quite a unique language in how it handles input and output in that it can cause quite some confusion for inexperienced “Haskellers”. While simple input and output operations in Haskell can look similar to its imperative equivalents, complex code can often lead to messy code. This is primarily because of how the internals of Haskell are made. With Haskell being a pure language, it simply does not want to break it’s purity, and this therefore means that I/O does not get a free pass to break it.
  2. Haskell is a purely functional programming, which is to say that mutability is generally absent and expressions have referential transparency. Purity and the accommodations required for it to function gracefully should not be underestimated as an influence on the rest of the language, and it is a powerful point of comparison. Where an impure language will change, a pure one will force you to recreate, modification is replaced by taking the original and creating something new using it. This has a great many benefits regarding predictability, consistency, and safety of programs, but it also induces a considerable change in mode of thought when programming. As one can imagine, having mutation pulled away from your toolkit can be a bewildering experience. Haskell also does not truly have statements, do-notation may superficially appear to reveal some sort of statements in the language, but this is mere syntactic sugar, though it does reflect quite powerfully how monads may be used to model imperative semantics. Referential transparency is a useful consequence of purity, and it implies that an expression may be replaced by the value it evaluates to without changing the program (This is only partially, it may change the actual computations done of course, but the point of the matter is that the results are the same.); a consequence which follows from referential transparency (possibly more aptly stated as a condition for its being to begin with) is that expressions may not have side effects. The utility of purity and transparency in this sense are the ease of which they allow a programmer to reason about their program, without mutation "change" only flows downward in scope, and it is easy to follow the logic of the program. In a Lua program, we may have global variables present alterable at any scope, a function call may change a variable above in scope, which you go on to use, and now you have been affected by this function in a way other than its pure return value. This mutability can make programming much easier but it can also make a program much more difficult to follow.
  3. However, to echo the common wisdom that no pure principle will survive practical work, purity, taken to its extreme, destabilized by its own rigidity, will pass over into its negation. In our case this manifests quite clearly in the realm of I/O, which presents a particularly intractable difficulty for any pure language. The reason why is clear to see when we consider how referential transparency could hold under output specifically, how can any expression sending the outside world arbitrary information and with the executive power to read arbitrary information in from the world be expected to be referentially transparent? How may any function be expected to be pure and give us the same results for the same inputs when it may read input from the outside world? The answer, of course, is that it may not be expected to do such a thing, and the languages solution to this situation is as cunning as it is practical. Monads have been anticipated in this discourse above, regarding imperative semantics, but they will find their true relevance now. Within Haskell, IO is to be done through a monad, which holds a value, and allows you to run a function using what it contains, however, the function must return (mandated and enforced by types) a value within the same monad. Thus, any I/O work cannot escape the monadic context. For example:
  4. main = do x <- getline
  5. reverse x
  6. putStr x
  7. Here we may use the line input arbitrarily, in our computations, but we may not take it outside of the monadic context. There simply is no method given to us to take a value of type IO String and extract that specific string out of the monad. Any means of accessing it must go through the bind operator, which forces us to return the value in the IO context .This practical solution also allows for some degree of mutability to be introduced, where you may have a reference to some value, the value being mutable, but all interactions must work within a monadic context. It is then a way of boxing in, as it were, impurity. This solution does, however, introduce additional difficulty for those learning the language, as it is an unusual and uncomfortable thing to deal with compared to an impure language such as Lua. There I/O is a considerably simpler process as purity must not be upheld and no category theoretic troubles must be introduced.
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement