3 ms·
I guess you haven’t spend too much time with Haskell. Haskell types especially generic ones are way more expressive and limit your search quite a bit. The funct
by betareduce 6y ago
I guess you haven’t spend too much time with Haskell. Haskell types especially generic ones are way more expressive and limit your search quite a bit. The function Int -> Int -> Bool can not reach for a database or anything other than the two Ints it is given.
- dmitriid 6y agoI guess I read the article and commented on what the article was saying and claiming. Hence the introductory sentences at the top of my post.
- tome 6y agoPerhaps when you wrote > Type signature `Int -> Int -> Bool` can be used for a function that does any of the following things [My emphasis] you meant "can't". That could be one explanation for the confusion that seems to have arisen here.
- magicalhippo 6y agoWhy couldn't it be a function that queries a database, like answering "on invoice x, does line y exist"? Genuinely curious, not that familiar with Haskell, just thought you could use something like parameter binding or similar to construct functions like that.
- ToJans 6y agoHaskell functions are pure, which means they can only access/use what is in their parameters, so unless you pass in some extra context (typically using a monad or an effect), you do not have access to the "outside world".
- magicalhippo 6y agoYou can bind parameters though in Haskell, no? I'm used to Boost.Bind and similar, so was thinking a scenario where you bind the database connection parameter and pass the resulting function to something else. As the sibling pointed out though, I now get that the result would be "tainted" so to speak.
- johnday 6y agoA database connection would operate either in IO (the generic "i am now talking to an unreliable outside world") monad, or some more specific monad. In this case you can think of a monad a bit like a computational context. If one is not present, you simply cannot[^1] instruct a Haskell program to perform those operations in a type safe way even if you give it a valid database connection identifier. [1] Well, you can, but if you do you're explicitly taking away all the safeguards that Haskell introduces, and it would never pass code review.
- uryga 6y agoif it has side-effects, it has to be something like Int -> Int -> IO Bool otherwise the type checker won't let you perform any side-effecting operations (btw Haskell's `IO Bool` would be spelled `IO<Bool>` in C++/Java syntax)
- magicalhippo 6y agoAnd there's no way to get rid of the IO then, presumably (I mean otherwise I could have just used that as a wrapper). edit: So at work, just about every value depends directly or indirectly on stuff that comes from files or from the database. So would they all have to be wrapped by IO?
- Twisol 6y agoIn Haskell, you often build pure transformations, and then lift them into an effectful context. If I have a function `String -> [String]`, say to parse a line of CSV into its elements, I can lift that to `IO String -> IO [String]` using the IO monad's `fmap`. And then I can compose it with something hypothetical like `readLine :: File -> IO String`, which actually reads the line. The core logic of a program often doesn't need to care deeply about state or system resources. Pure functional programming is about writing as much as you can in this "functional core", and then lifting the assembled pieces of pipeline into the "imperative shell" (such as the IO monad).
- magicalhippo 6y agoOk, so you make pure functions and turn them dirty, so to speak. Makes sense. In our case, almost all core code depends on various parameters, which come from the database. For example, GB recently left the EU so everything involving GB is now processed under different rules, except old stuff which has to be processed under the old rules. Thus being part of EU or not is a date-dependent database query (it already was, not the first time a country's EU status has changed). So if I get your explanation correctly, I'd code the core logic as if these parameters were pure, side-effect free, which would make the core logic side-effect free. In the case above, I'd pass a function which maps a (pure) date and string into a (pure) bool, to test for EU membership. I'd then turn that whole thing dirty via the IO thingy, passing "IO parameters" and receiving "IO results", so I can pass it my EU test function which does a database query. edit: And I presume my "dirty" database-connecting function can also mutate things, so it can do caching. Don't want to hit that database too often.