help with IO guards

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

help with IO guards

Miro Karpis
Hi,

please is there a way to have guards with 'where' that communicates with
IO? Or is there some other more elegant way? I can do this with classic
if/else,...but I just find it nicer with guards.


I have something like this (just an example):


f :: Int -> IO String
f x
    | null dbOutput = return "no db record"
    | otherwise = return "we got some db records"
    where dbOutput = getDBRecord x


getDBRecord :: Int -> IO [Int]
getDBRecord recordId = do
    putStrLn $ "checking dbRecord" ++ show recordId
    --getting data from DB
    return [1,2]


problem is that db dbOutput is IO and the guard check does not like it:

Couldn't match expected type ?[a0]? with actual type ?IO [Int]?
    In the first argument of ?null?, namely ?dbOutput?
    In the expression: null dbOutput



Cheers,
Miro
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20150115/79289d65/attachment.html>

Reply | Threaded
Open this post in threaded view
|

help with IO guards

Julian Birch
Here's how I would do it:

Write two functions. One (f) takes the int and gets the IO record. One
(g) takes a (non-IO) record and returns the string. Now you can use a bind
(=<<) to combine the two.

Once you've got that working, you can move the bits into the where clause
of your original function.

Hope this helps.

J

On Thursday, January 15, 2015, Miro Karpis <miroslav.karpis at gmail.com>
wrote:

> Hi,
>
> please is there a way to have guards with 'where' that communicates with
> IO? Or is there some other more elegant way? I can do this with classic
> if/else,...but I just find it nicer with guards.
>
>
> I have something like this (just an example):
>
>
> f :: Int -> IO String
> f x
>     | null dbOutput = return "no db record"
>     | otherwise = return "we got some db records"
>     where dbOutput = getDBRecord x
>
>
> getDBRecord :: Int -> IO [Int]
> getDBRecord recordId = do
>     putStrLn $ "checking dbRecord" ++ show recordId
>     --getting data from DB
>     return [1,2]
>
>
> problem is that db dbOutput is IO and the guard check does not like it:
>
> Couldn't match expected type ?[a0]? with actual type ?IO [Int]?
>     In the first argument of ?null?, namely ?dbOutput?
>     In the expression: null dbOutput
>
>
>
> Cheers,
> Miro
>


--
Sent from an iPhone, please excuse brevity and typos.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20150115/b8d237eb/attachment.html>

Reply | Threaded
Open this post in threaded view
|

help with IO guards

Dimitri DeFigueiredo
In reply to this post by Miro Karpis
I would not say that the problem is with the guard check. The problem is
with 'null'. It's type is

Prelude> :t null
null :: [a] -> Bool

So, it expects a list of something, rather than an IO of something,
whence the complaint.

Dimitri


On 15/01/15 09:51, Miro Karpis wrote:

> Hi,
>
> please is there a way to have guards with 'where' that communicates
> with IO? Or is there some other more elegant way? I can do this with
> classic if/else,...but I just find it nicer with guards.
>
>
> I have something like this (just an example):
>
>
> f :: Int -> IO String
> f x
>     | null dbOutput = return "no db record"
>     | otherwise = return "we got some db records"
>     where dbOutput = getDBRecord x
>
>
> getDBRecord :: Int -> IO [Int]
> getDBRecord recordId = do
>     putStrLn $ "checking dbRecord" ++ show recordId
>     --getting data from DB
>     return [1,2]
>
>
> problem is that db dbOutput is IO and the guard check does not like it:
>
> Couldn't match expected type ?[a0]? with actual type ?IO [Int]?
>     In the first argument of ?null?, namely ?dbOutput?
>     In the expression: null dbOutput
>
>
>
> Cheers,
> Miro
>
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20150115/e40a0c92/attachment.html>

Reply | Threaded
Open this post in threaded view
|

help with IO guards

Mike Meyer
On Thu, Jan 15, 2015 at 9:24 AM, Dimitri DeFigueiredo <
defigueiredo at ucdavis.edu> wrote:

>  I would not say that the problem is with the guard check. The problem is
> with 'null'. It's type is
>
> Prelude> :t null
> null :: [a] -> Bool
>
> So, it expects a list of something, rather than an IO of something, whence
> the complaint.
>


While that's the source of the error, the problem is the combination of the
guard check and where to bind a value in the IO monad.

Guard checks must have a value of Bool. getDBRecord returns something of
type IO [Int]. Where just binds a name, so you either need a way to extract
the [Int] from the return value before binding it in the where, or a
function of type IO [Int] -> Bool for the guard.

Note that this isn't an IO issue but a monad issue. There isn't a monad
method that returns a value not in the monad, so you can't  write either of
the two options above using monad methods. The best solution is the one
already proposed - write a function from [Int] -> IO String, and use bind
(>>=) on that function to handle things. You could also use the do sugaring
of <- to get a less functional version.

The last option is to use the IO-specific function unsafePerformIO to write
something like nullIO = null . unsafePerformIO. But it's called UNSAFE and
tucked away in a module of similar operations for a reason. Using bind is
much preferred.


> On 15/01/15 09:51, Miro Karpis wrote:
>
>   Hi,
>
>  please is there a way to have guards with 'where' that communicates with
> IO? Or is there some other more elegant way? I can do this with classic
> if/else,...but I just find it nicer with guards.
>
>
>  I have something like this (just an example):
>
>
> f :: Int -> IO String
> f x
>     | null dbOutput = return "no db record"
>     | otherwise = return "we got some db records"
>     where dbOutput = getDBRecord x
>
>
> getDBRecord :: Int -> IO [Int]
> getDBRecord recordId = do
>     putStrLn $ "checking dbRecord" ++ show recordId
>     --getting data from DB
>     return [1,2]
>
>
>  problem is that db dbOutput is IO and the guard check does not like it:
>
> Couldn't match expected type ?[a0]? with actual type ?IO [Int]?
>     In the first argument of ?null?, namely ?dbOutput?
>     In the expression: null dbOutput
>
>
>
>  Cheers,
>  Miro
>
>
> _______________________________________________
> Beginners mailing listBeginners at haskell.orghttp://www.haskell.org/mailman/listinfo/beginners
>
>
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20150115/ff8a16b9/attachment.html>

Reply | Threaded
Open this post in threaded view
|

help with IO guards

Miro Karpis
Many thanks everyone,.. but I'm not so confident with monads. If I
understand I could translate with them for example IO String to String? If
this is true I'm having troubles to achieve this.

Here is my simple test (only to test the logic), which ends with error:

 Couldn't match type ?[]? with ?IO?
    Expected type: IO Char
      Actual type: String
    In the expression: f a
    In the second argument of ?(>>=)?, namely ?(\ a -> f a)?



g = readLn
    >>= (\a -> f a)

f :: String -> String
f s_ = s_ ++ "!"



Cheers, Miro

On Thu, Jan 15, 2015 at 5:42 PM, Mike Meyer <mwm at mired.org> wrote:

> On Thu, Jan 15, 2015 at 9:24 AM, Dimitri DeFigueiredo <
> defigueiredo at ucdavis.edu> wrote:
>
>>  I would not say that the problem is with the guard check. The problem is
>> with 'null'. It's type is
>>
>> Prelude> :t null
>> null :: [a] -> Bool
>>
>> So, it expects a list of something, rather than an IO of something,
>> whence the complaint.
>>
>
>
> While that's the source of the error, the problem is the combination of
> the guard check and where to bind a value in the IO monad.
>
> Guard checks must have a value of Bool. getDBRecord returns something of
> type IO [Int]. Where just binds a name, so you either need a way to extract
> the [Int] from the return value before binding it in the where, or a
> function of type IO [Int] -> Bool for the guard.
>
> Note that this isn't an IO issue but a monad issue. There isn't a monad
> method that returns a value not in the monad, so you can't  write either of
> the two options above using monad methods. The best solution is the one
> already proposed - write a function from [Int] -> IO String, and use bind
> (>>=) on that function to handle things. You could also use the do sugaring
> of <- to get a less functional version.
>
> The last option is to use the IO-specific function unsafePerformIO to
> write something like nullIO = null . unsafePerformIO. But it's called
> UNSAFE and tucked away in a module of similar operations for a reason.
> Using bind is much preferred.
>
>
>> On 15/01/15 09:51, Miro Karpis wrote:
>>
>>   Hi,
>>
>>  please is there a way to have guards with 'where' that communicates with
>> IO? Or is there some other more elegant way? I can do this with classic
>> if/else,...but I just find it nicer with guards.
>>
>>
>>  I have something like this (just an example):
>>
>>
>> f :: Int -> IO String
>> f x
>>     | null dbOutput = return "no db record"
>>     | otherwise = return "we got some db records"
>>     where dbOutput = getDBRecord x
>>
>>
>> getDBRecord :: Int -> IO [Int]
>> getDBRecord recordId = do
>>     putStrLn $ "checking dbRecord" ++ show recordId
>>     --getting data from DB
>>     return [1,2]
>>
>>
>>  problem is that db dbOutput is IO and the guard check does not like it:
>>
>> Couldn't match expected type ?[a0]? with actual type ?IO [Int]?
>>     In the first argument of ?null?, namely ?dbOutput?
>>     In the expression: null dbOutput
>>
>>
>>
>>  Cheers,
>>  Miro
>>
>>
>> _______________________________________________
>> Beginners mailing listBeginners at haskell.orghttp://www.haskell.org/mailman/listinfo/beginners
>>
>>
>>
>> _______________________________________________
>> Beginners mailing list
>> Beginners at haskell.org
>> http://www.haskell.org/mailman/listinfo/beginners
>>
>>
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20150115/38220903/attachment-0001.html>

Reply | Threaded
Open this post in threaded view
|

help with IO guards

Mike Meyer
f has the wrong type. It needs to return a value in the IO monad. For
instance:

f: String -> IO String
f s = return (s ++ "!")

g :: IO String
g = readLn >>= f

You could also let f return a value of a type other than String, say:

f :: String -> IO ()
f = print

The type of >>= tells you this: Monad m => m a -> (a -> m b) -> m b. The
second argument has type a -> m b. String -> IO () or String -> IO String
both match that.

As a warning, readLn expects a Haskell value, and f requires that it be a
string. So you have to type in a string the way you would in a program, as
"Hello" or ['H', 'e', 'l', 'l', 'o'] or you'll get a parse failure.

On Thu, Jan 15, 2015 at 2:44 PM, Miro Karpis <miroslav.karpis at gmail.com>
wrote:

> Many thanks everyone,.. but I'm not so confident with monads. If I
> understand I could translate with them for example IO String to String? If
> this is true I'm having troubles to achieve this.
>
> Here is my simple test (only to test the logic), which ends with error:
>
>  Couldn't match type ?[]? with ?IO?
>     Expected type: IO Char
>       Actual type: String
>     In the expression: f a
>     In the second argument of ?(>>=)?, namely ?(\ a -> f a)?
>
>
>
> g = readLn
>     >>= (\a -> f a)
>
> f :: String -> String
> f s_ = s_ ++ "!"
>
>
>
> Cheers, Miro
>
> On Thu, Jan 15, 2015 at 5:42 PM, Mike Meyer <mwm at mired.org> wrote:
>
>> On Thu, Jan 15, 2015 at 9:24 AM, Dimitri DeFigueiredo <
>> defigueiredo at ucdavis.edu> wrote:
>>
>>>  I would not say that the problem is with the guard check. The problem
>>> is with 'null'. It's type is
>>>
>>> Prelude> :t null
>>> null :: [a] -> Bool
>>>
>>> So, it expects a list of something, rather than an IO of something,
>>> whence the complaint.
>>>
>>
>>
>> While that's the source of the error, the problem is the combination of
>> the guard check and where to bind a value in the IO monad.
>>
>> Guard checks must have a value of Bool. getDBRecord returns something of
>> type IO [Int]. Where just binds a name, so you either need a way to extract
>> the [Int] from the return value before binding it in the where, or a
>> function of type IO [Int] -> Bool for the guard.
>>
>> Note that this isn't an IO issue but a monad issue. There isn't a monad
>> method that returns a value not in the monad, so you can't  write either of
>> the two options above using monad methods. The best solution is the one
>> already proposed - write a function from [Int] -> IO String, and use bind
>> (>>=) on that function to handle things. You could also use the do sugaring
>> of <- to get a less functional version.
>>
>> The last option is to use the IO-specific function unsafePerformIO to
>> write something like nullIO = null . unsafePerformIO. But it's called
>> UNSAFE and tucked away in a module of similar operations for a reason.
>> Using bind is much preferred.
>>
>>
>>> On 15/01/15 09:51, Miro Karpis wrote:
>>>
>>>   Hi,
>>>
>>>  please is there a way to have guards with 'where' that communicates
>>> with IO? Or is there some other more elegant way? I can do this with
>>> classic if/else,...but I just find it nicer with guards.
>>>
>>>
>>>  I have something like this (just an example):
>>>
>>>
>>> f :: Int -> IO String
>>> f x
>>>     | null dbOutput = return "no db record"
>>>     | otherwise = return "we got some db records"
>>>     where dbOutput = getDBRecord x
>>>
>>>
>>> getDBRecord :: Int -> IO [Int]
>>> getDBRecord recordId = do
>>>     putStrLn $ "checking dbRecord" ++ show recordId
>>>     --getting data from DB
>>>     return [1,2]
>>>
>>>
>>>  problem is that db dbOutput is IO and the guard check does not like it:
>>>
>>> Couldn't match expected type ?[a0]? with actual type ?IO [Int]?
>>>     In the first argument of ?null?, namely ?dbOutput?
>>>     In the expression: null dbOutput
>>>
>>>
>>>
>>>  Cheers,
>>>  Miro
>>>
>>>
>>> _______________________________________________
>>> Beginners mailing listBeginners at haskell.orghttp://www.haskell.org/mailman/listinfo/beginners
>>>
>>>
>>>
>>> _______________________________________________
>>> Beginners mailing list
>>> Beginners at haskell.org
>>> http://www.haskell.org/mailman/listinfo/beginners
>>>
>>>
>>
>> _______________________________________________
>> Beginners mailing list
>> Beginners at haskell.org
>> http://www.haskell.org/mailman/listinfo/beginners
>>
>>
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20150115/66ef96a9/attachment.html>

Reply | Threaded
Open this post in threaded view
|

help with IO guards

Marcin Mrotek
In reply to this post by Miro Karpis
Hello,

A list ([]) is also a monad, and a String is defined as a list of
characters ([Char]). So in your example, it's as if you were trying to
use (>>=) operator on two different monads ([] and IO), which is
impossible. To make a pure value a monadic value, you need to use
return:

g = readLn >>= (\a -> return (f a))

which is equivalent to composing f with return:

g = readLn >>= return.f

Regards,
Marcin

Reply | Threaded
Open this post in threaded view
|

help with IO guards

Julian Birch
Going back to an earlier question: a monad is a bit like a roach motel. You
can check in but you can't leave. (This isn't true of every Monad, but the
point is there's no guarantees.) In particular, you can't go from IO String
to String _at all_. But you can, through Functor, pass it to a function
that takes a plain String. And through Monad, you can turn IO (IO String)
back to IO String.

Hope this helps.

On Thursday, January 15, 2015, Marcin Mrotek <marcin.jan.mrotek at gmail.com>
wrote:

> Hello,
>
> A list ([]) is also a monad, and a String is defined as a list of
> characters ([Char]). So in your example, it's as if you were trying to
> use (>>=) operator on two different monads ([] and IO), which is
> impossible. To make a pure value a monadic value, you need to use
> return:
>
> g = readLn >>= (\a -> return (f a))
>
> which is equivalent to composing f with return:
>
> g = readLn >>= return.f
>
> Regards,
> Marcin
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org <javascript:;>
> http://www.haskell.org/mailman/listinfo/beginners
>


--
Sent from an iPhone, please excuse brevity and typos.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20150115/af1423e4/attachment.html>

Reply | Threaded
Open this post in threaded view
|

help with IO guards

Miro Karpis
many thanks,....but then I unfortunately don't understand how can I fix my
initial problem:

to use IO check in guards - is that possible?

Regards,
Miro

On Thu, Jan 15, 2015 at 10:12 PM, Julian Birch <julian.birch at gmail.com>
wrote:

> Going back to an earlier question: a monad is a bit like a roach motel.
> You can check in but you can't leave. (This isn't true of every Monad, but
> the point is there's no guarantees.) In particular, you can't go from IO
> String to String _at all_. But you can, through Functor, pass it to a
> function that takes a plain String. And through Monad, you can turn IO
> (IO String) back to IO String.
>
> Hope this helps.
>
>
> On Thursday, January 15, 2015, Marcin Mrotek <marcin.jan.mrotek at gmail.com>
> wrote:
>
>> Hello,
>>
>> A list ([]) is also a monad, and a String is defined as a list of
>> characters ([Char]). So in your example, it's as if you were trying to
>> use (>>=) operator on two different monads ([] and IO), which is
>> impossible. To make a pure value a monadic value, you need to use
>> return:
>>
>> g = readLn >>= (\a -> return (f a))
>>
>> which is equivalent to composing f with return:
>>
>> g = readLn >>= return.f
>>
>> Regards,
>> Marcin
>> _______________________________________________
>> Beginners mailing list
>> Beginners at haskell.org
>> http://www.haskell.org/mailman/listinfo/beginners
>>
>
>
> --
> Sent from an iPhone, please excuse brevity and typos.
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20150115/ef3d45f8/attachment-0001.html>

Reply | Threaded
Open this post in threaded view
|

help with IO guards

Julian Birch
Not really, for the same reason: a guard needs a Bool, and you can't get a
Bool from IO Bool.

On Thursday, January 15, 2015, Miro Karpis <miroslav.karpis at gmail.com>
wrote:

> many thanks,....but then I unfortunately don't understand how can I fix my
> initial problem:
>
> to use IO check in guards - is that possible?
>
> Regards,
> Miro
>
> On Thu, Jan 15, 2015 at 10:12 PM, Julian Birch <julian.birch at gmail.com
> <javascript:_e(%7B%7D,'cvml','julian.birch at gmail.com');>> wrote:
>
>> Going back to an earlier question: a monad is a bit like a roach motel.
>> You can check in but you can't leave. (This isn't true of every Monad, but
>> the point is there's no guarantees.) In particular, you can't go from IO
>> String to String _at all_. But you can, through Functor, pass it to a
>> function that takes a plain String. And through Monad, you can turn IO
>> (IO String) back to IO String.
>>
>> Hope this helps.
>>
>>
>> On Thursday, January 15, 2015, Marcin Mrotek <marcin.jan.mrotek at gmail.com
>> <javascript:_e(%7B%7D,'cvml','marcin.jan.mrotek at gmail.com');>> wrote:
>>
>>> Hello,
>>>
>>> A list ([]) is also a monad, and a String is defined as a list of
>>> characters ([Char]). So in your example, it's as if you were trying to
>>> use (>>=) operator on two different monads ([] and IO), which is
>>> impossible. To make a pure value a monadic value, you need to use
>>> return:
>>>
>>> g = readLn >>= (\a -> return (f a))
>>>
>>> which is equivalent to composing f with return:
>>>
>>> g = readLn >>= return.f
>>>
>>> Regards,
>>> Marcin
>>> _______________________________________________
>>> Beginners mailing list
>>> Beginners at haskell.org
>>> http://www.haskell.org/mailman/listinfo/beginners
>>>
>>
>>
>> --
>> Sent from an iPhone, please excuse brevity and typos.
>>
>
>

--
Sent from an iPhone, please excuse brevity and typos.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20150115/b656f21c/attachment.html>

Reply | Threaded
Open this post in threaded view
|

help with IO guards

Christopher Allen
In reply to this post by Julian Birch
I haven't seen anybody explain the real reasons you can't yank `a` out of
something of type `IO a`, so I thought I'd attempt to clear a few things up.

It's true that you cannot *in general* extract a value of type `a` from
something of type `Monad m => m a` but those reasons are *not* why you
can't in the case of IO. You can't with Monad in general because the
typeclass doesn't provide a method with the type `m a -> a`, in fact, it
only provides the opposite: `a -> m a`.

The real reason you can't pattern match on or otherwise extract values from
IO is that it's an abstract datatype - on purpose. The constructor is not
exported, the internals are hidden.

You are using a non-strict programming language. The IO datatype is how the
implementation knows not to replace the thunk with its value when evaluated.

Want to see what I mean?

Play with some code that uses
https://hackage.haskell.org/package/time-1.3/docs/Data-Time-Clock.html#v:getCurrentTime
to get the current time. Note how each time you force evaluation of the `IO
UTCTime` you're getting a new UTCTime each time. Then wrap it in
`unsafePerformIO` - it'll only get executed once. This is *definitely* not
the semantics you want, you're too new to know when you'd want the unsafe*
functions for now.

If you aren't comfortable with monads, no amount of thrashing is going to
let you avoid using Functor/Applicative/Monad if you want to interact with
values produced in IO.

I wrote a guide for learning Haskell, it covers Functor/Applicative/Monad
which are *everywhere* - not just for use with IO. This is the guide:
https://github.com/bitemyapp/learnhaskell

There are people used to teaching and assisting with the courses
recommended in my guide (cis194 & NICTA course) on Freenode IRC at
#haskell-beginners. There are tons of people equipped to help you in
#haskell as well.

--- Chris Allen


On Thu, Jan 15, 2015 at 3:12 PM, Julian Birch <julian.birch at gmail.com>
wrote:

> Going back to an earlier question: a monad is a bit like a roach motel.
> You can check in but you can't leave. (This isn't true of every Monad, but
> the point is there's no guarantees.) In particular, you can't go from IO
> String to String _at all_. But you can, through Functor, pass it to a
> function that takes a plain String. And through Monad, you can turn IO
> (IO String) back to IO String.
>
> Hope this helps.
>
>
> On Thursday, January 15, 2015, Marcin Mrotek <marcin.jan.mrotek at gmail.com>
> wrote:
>
>> Hello,
>>
>> A list ([]) is also a monad, and a String is defined as a list of
>> characters ([Char]). So in your example, it's as if you were trying to
>> use (>>=) operator on two different monads ([] and IO), which is
>> impossible. To make a pure value a monadic value, you need to use
>> return:
>>
>> g = readLn >>= (\a -> return (f a))
>>
>> which is equivalent to composing f with return:
>>
>> g = readLn >>= return.f
>>
>> Regards,
>> Marcin
>> _______________________________________________
>> Beginners mailing list
>> Beginners at haskell.org
>> http://www.haskell.org/mailman/listinfo/beginners
>>
>
>
> --
> Sent from an iPhone, please excuse brevity and typos.
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20150115/75061d30/attachment.html>

Reply | Threaded
Open this post in threaded view
|

help with IO guards

Miro Karpis
many thanks! I will take a look at it.

cheers and thanks to all :-)

On Thu, Jan 15, 2015 at 10:28 PM, Christopher Allen <cma at bitemyapp.com>
wrote:

> I haven't seen anybody explain the real reasons you can't yank `a` out of
> something of type `IO a`, so I thought I'd attempt to clear a few things up.
>
> It's true that you cannot *in general* extract a value of type `a` from
> something of type `Monad m => m a` but those reasons are *not* why you
> can't in the case of IO. You can't with Monad in general because the
> typeclass doesn't provide a method with the type `m a -> a`, in fact, it
> only provides the opposite: `a -> m a`.
>
> The real reason you can't pattern match on or otherwise extract values
> from IO is that it's an abstract datatype - on purpose. The constructor is
> not exported, the internals are hidden.
>
> You are using a non-strict programming language. The IO datatype is how
> the implementation knows not to replace the thunk with its value when
> evaluated.
>
> Want to see what I mean?
>
> Play with some code that uses
> https://hackage.haskell.org/package/time-1.3/docs/Data-Time-Clock.html#v:getCurrentTime
> to get the current time. Note how each time you force evaluation of the `IO
> UTCTime` you're getting a new UTCTime each time. Then wrap it in
> `unsafePerformIO` - it'll only get executed once. This is *definitely* not
> the semantics you want, you're too new to know when you'd want the unsafe*
> functions for now.
>
> If you aren't comfortable with monads, no amount of thrashing is going to
> let you avoid using Functor/Applicative/Monad if you want to interact with
> values produced in IO.
>
> I wrote a guide for learning Haskell, it covers Functor/Applicative/Monad
> which are *everywhere* - not just for use with IO. This is the guide:
> https://github.com/bitemyapp/learnhaskell
>
> There are people used to teaching and assisting with the courses
> recommended in my guide (cis194 & NICTA course) on Freenode IRC at
> #haskell-beginners. There are tons of people equipped to help you in
> #haskell as well.
>
> --- Chris Allen
>
>
> On Thu, Jan 15, 2015 at 3:12 PM, Julian Birch <julian.birch at gmail.com>
> wrote:
>
>> Going back to an earlier question: a monad is a bit like a roach motel.
>> You can check in but you can't leave. (This isn't true of every Monad, but
>> the point is there's no guarantees.) In particular, you can't go from IO
>> String to String _at all_. But you can, through Functor, pass it to a
>> function that takes a plain String. And through Monad, you can turn IO
>> (IO String) back to IO String.
>>
>> Hope this helps.
>>
>>
>> On Thursday, January 15, 2015, Marcin Mrotek <marcin.jan.mrotek at gmail.com>
>> wrote:
>>
>>> Hello,
>>>
>>> A list ([]) is also a monad, and a String is defined as a list of
>>> characters ([Char]). So in your example, it's as if you were trying to
>>> use (>>=) operator on two different monads ([] and IO), which is
>>> impossible. To make a pure value a monadic value, you need to use
>>> return:
>>>
>>> g = readLn >>= (\a -> return (f a))
>>>
>>> which is equivalent to composing f with return:
>>>
>>> g = readLn >>= return.f
>>>
>>> Regards,
>>> Marcin
>>> _______________________________________________
>>> Beginners mailing list
>>> Beginners at haskell.org
>>> http://www.haskell.org/mailman/listinfo/beginners
>>>
>>
>>
>> --
>> Sent from an iPhone, please excuse brevity and typos.
>>
>> _______________________________________________
>> Beginners mailing list
>> Beginners at haskell.org
>> http://www.haskell.org/mailman/listinfo/beginners
>>
>>
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20150115/516c876e/attachment-0001.html>

Reply | Threaded
Open this post in threaded view
|

help with IO guards

Sylvain HENRY
In reply to this post by Miro Karpis
Hi,

Using LambdaCase extension, you can write something quite elegant:

{-# LANGUAGE LambdaCase #-}

f :: Int -> IO String
f x = getDBRecord x >>= \case
    dbOutput
        | null dbOutput -> return "no db record"
        | otherwise      -> return "we got some db records"

Or better:

f :: Int -> IO String
f x = getDBRecord x >>= \case
          [] -> return "no db record"
          _  -> return "we got some db records"

But you can also use another function for the pure part:

recordMsg :: [a] -> String
recordMsg [] = "no db record"
recordMsg _ = "we got some db records"

f :: Int -> IO String
f = fmap recordMsg . getDBRecord

Regards,
Sylvain


2015-01-15 12:51 GMT+01:00 Miro Karpis <miroslav.karpis at gmail.com>:

> Hi,
>
> please is there a way to have guards with 'where' that communicates with
> IO? Or is there some other more elegant way? I can do this with classic
> if/else,...but I just find it nicer with guards.
>
>
> I have something like this (just an example):
>
>
> f :: Int -> IO String
> f x
>     | null dbOutput = return "no db record"
>     | otherwise = return "we got some db records"
>     where dbOutput = getDBRecord x
>
>
> getDBRecord :: Int -> IO [Int]
> getDBRecord recordId = do
>     putStrLn $ "checking dbRecord" ++ show recordId
>     --getting data from DB
>     return [1,2]
>
>
> problem is that db dbOutput is IO and the guard check does not like it:
>
> Couldn't match expected type ?[a0]? with actual type ?IO [Int]?
>     In the first argument of ?null?, namely ?dbOutput?
>     In the expression: null dbOutput
>
>
>
> Cheers,
> Miro
>
> _______________________________________________
> Beginners mailing list
> Beginners at haskell.org
> http://www.haskell.org/mailman/listinfo/beginners
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.haskell.org/pipermail/beginners/attachments/20150123/2243ce7f/attachment.html>