5 ms·
Using side effects in Haskell is easy. The only thing is that they need to be explicit and you aren't allowed to hide them inside pure functions. For a databas
by ufo 13y ago
Using side effects in Haskell is easy. The only thing is that they need to be explicit and you aren't allowed to hide them inside pure functions.
For a database example, here is the chapter from Real World Haskell about databases (a bit old but still relevant):
http://book.realworldhaskell.org/read/using-databases.html http://book.realworldhaskell.org/read/using-databases.html
And here is some example code:
do
conn <- connectSqlite3 "test1.db"
stmt <- prepare conn "INSERT INTO test VALUES (?, ?)"
execute stmt [toSql 1, toSql "one"]
execute stmt [toSql 2, toSql "two"]
execute stmt [toSql 3, toSql "three"]
execute stmt [toSql 4, SqlNull]
commit conn
disconnect conn
As you can see, it looks very similar to how you would write it in a regular imperative language. The main difference is that since they database operations are IO operations then they need to be in the special do-notation block and cannot be mixed with regular code.
As for the question of wanting to mix pure and impure code that much I don't think it actually comes up that much. First of all, I find that I don't often find myself with an impure function that I want to add a side effect in the middle seamlessly - firstly, side-effecting stuff tend to be side-effecting from the beggining and secondly if I do want to turn a pure function into an impure one then forcing me to change the interface helps make sure that I am not breaking any code that used to work because it assumed it was working with pure code. Additionally, Haskell is really good at abstracting code so its not that hard to take a big chunk of logic and split it into a pure and an impure part. Finally, converting code from pure to impure is not that bad - sure, you need to change the syntax a bit but the type checker helps you find all the places that need to change and also helps you check all the code that calles the method you changed so you can be sure that you aren't breaking those.
side effecting operations in the IO monad so you can't run them in the middle of any function and instead must run them inside a special "do-notation block" like I did.
You can have impure code call both other impure code and pure functions and all you can't do is call impure functions from inside pure functions. Sure, its a bit annoying if you ever have to convert a pure function to an impure one (you need to change some of the syntax and all the places that call tha tfunction need to start treating it as impure) but its not that bad: first of all the type checker tells you all the spots where you need to update your code and secondly, Haskell is super good at abstracting code so its not hard to take a big chunk of code with some side effects in the middle and split it into a pure and an impure part.
> to academic program
Its a little pet peeve of mine but it seems that nowadays "academic" doesn't have a real meaning and just tends to refer to whatever people don't like. :)
- dllthomas 13y ago"do" is just syntax. You could write the above as: connectSqlite3 "test1.db" >>= \ conn -> prepare conn "INSERT INTO test VALUES (?, ?)" >>= \ stmt -> >> execute stmt [toSql 1, toSql "one"] >> execute stmt [toSql 2, toSql "two"] >> execute stmt [toSql 3, toSql "three"] >> execute stmt [toSql 4, SqlNull] >> commit conn >> disconnect conn and it's "just" a bunch of nested lambdas with no "do" in sight. What's different from "regular" code is that those lambdas 1) return IO actions, and 2) are strung together with monadic bind (>>=) to build one big IO action. To be sure, in this case the do version is much easier to read (that's why "do notation" exists). It can be used with any monad, though - nothing ties it particularly to IO.
- ufo 13y agoMaybe I should have been clearer but the basic point is that monadic code has a different interface bar (foo x) --pure Haskell vs foo x >>= bar --monadic Haskell vs bar(foo(x)) -- in C you write both cases like this.
- dllthomas 13y agoYou're close, but it's not really so clear cut. foo x ++ bar -- "pure" or "monadic"? foo x >>= baz -- "pure" or "monadic"? What if (foo x) is a list in both cases? (>>=) is just an operator. The values that it operates on are anything with a Monad instance, just like the values that (+) operates on are anything with a Num instance. There is nothing voodoo about monads or about bind (>>=); such voodoo as there is lies solely in IO, which is interacted with the same way as other values (though certainly what you can do with (IO a) is more limited than what you can do with (Maybe a)).
- Dewie 13y agoI used to think that Monad was some alternative realm in Haskell, a realm where purity didn't exist and everything was written in an alternative, built-in language (do-notation). That's because people tend to refer to using Monads as "working in the X-Monad", as if it is some... place. But then it turned out... Oh, so it's basically just a signature/interface/type class.