[Haskell-beginners] function not working as expected, type issues
Gesh
gesh at gesh.uni.cx
Wed Apr 9 08:45:09 UTC 2014
On April 9, 2014 9:03:54 AM GMT+03:00, Alexej Magura <sickhadas at gmail.com> wrote:
>K, so I have a function that I’m writing that takes a *string* and a
>*count* and prints the *string* to STDOUT *count* times:
>
>displayD :: IO () -> String -> Int
>displayD string count = do
> (count > 0) && hPutStr stdout string
> (count > 0) && displayD string (count - 1)
>
>However, when I try to compile the file, I get several errors; here’s a
>pastebin: http://pastebin.com/DEsuAvfz
>
The errors you see here are caused by GHC trying to make sense of what you wrote and failing. This is because the code you wrote isn't well-typed - that is, you're using values of types differing from the types GHC is expecting you to use. More on this below.
>What I’m trying to do here is check to see if *count* is greater than
>0, and then if it is, then I’d like to print *string* to STDOUT until
>*count* equals 0. I tried doing it via pattern matching, like so:
>
Thank you for explaining the problem you're trying to solve instead of Gesh
problem you're facing. Most people don't have the decency to do that, leading to hours of pointless discussion. [0]
>displayD string (count > 0) = do
>
>But I haven’t seen any examples of how to do pattern matching in
>functions using *do*, that is *IO*, so I’m unsure if the above is even
>anywhere near correct.
>
do-blocks are no different from any other expression in Haskell when it comes to pattern-matching. I'd suggest starting out with a pure (no IO) version of your code, loading it into GHCi and playing around with it, then adding the IO once you feel comfortable with writing pure code. In general, it's considered good practice to separate impure code from pure code. In this case, that would mean creating a function returning the n-time self a concatenation of a string, then printing the result of that function elsewhere.
>Still very uncomfortable with declaring function types: I have a hard
>time figuring out which type is returned and what type is expected as
>an arg. My initial guess is that the *first* type specified is the one
>returned, but I’m not sure.
>
I'm curious as to why you thought that. The directionality of the arrows in a type signature is quite clear, at least to me. a -> b is the type of functions *from* a *to* b. This is important to understand, especially once you start treading into higher-order-function-land, using functions such as map :: (a -> b) -> [a] -> [b] (can you guess what it does and how it does it? Can you do that just by looking at the type?).
One further note. The errors you saw in your output were caused by this misunderstanding of function types, as well as a misunderstanding of the types do-blocks expect. From your coding style, it appears that you think of && in the way Bash does - as the function:
> p && x = if p then x else *nothing*
For some suitable *nothing*. However, this is not the case. Firstly, && is just a function that takes two values of type Book and returns True if both of them are True. Second, a function such as the one I described above exists for Monads, by the name of guard. But until you grasp pure Haskell, there is no point in confusing yourself with them yet.
Anyway, all of the above means that passing a non-Bool value to && is not acceptable, and since hPutStr stdout string is not a value of type Bool, GHC complains.
So, in brief, follow the arrows, values are not automatically cast as in other languages, && is not the guard operator from Bash, and get away from IO for your first couple of attempts with Haskell.
Hoping to help,
Gesh
[0] - http://xyproblem.info/
Alexej,
You have several things going on here.
More information about the Beginners
mailing list