using interact with state, was Re: [Haskell-cafe] applicative
challenge
Thomas Hartman
tphyahoo at gmail.com
Tue May 5 15:30:47 EDT 2009
Aha!
There is in fact a way to fit this specification into the applicative paradigm.
I'm a bit muzzy as to what it all means, but I must say, aesthetically
I'm rather pleased with the result:
module Main where
import Control.Monad.State
import Control.Applicative
import Control.Applicative.State -- applicative-extras on hackage
-- works
t18 = interact $ evalState f18
where f18 = return paint `ap` grabTillBlank `ap` grabTillBlank
paint first second = "first\n" ++ first ++ "second\n" ++ second
grabTillBlank = State $ \s ->
let (beg,end) = break null . lines $ s
in (unlines beg, (unlines . drop 2 $ end))
-- And, with applicative extras:
t19 = interact $ evalState f19
where f19 = paint <$> grabTillBlank <*> grabTillBlank
paint first second = "first\n" ++ first ++ "second\n" ++ second
2009/5/5 Thomas Hartman <tphyahoo at gmail.com>:
>> interact (\s -> let (first,second) = span (not . null) (lines s)
> in unlines ("first":first++"second":takeWhile (not.null) second))
>
> So, that didn't quite do the right thing, and it seemed like using
> span/break wouldn't scale well for more than two iterations. Here's
> another attempt, which is a little closer I think, except that it
> seems to be using some sort of half-assed state without being explicit
> about it:
>
> module Main where
>
> t17 = interact f17
> f17 s = let (first,rest) = grabby s
> (second,_) = grabby rest
> in "first\n" ++ first ++ "second\n" ++ second
>
> grabby :: String -> (String,String)
> grabby s =
> let (beg,end) = break null . lines $ s
> in (unlines beg, (unlines . drop 2 $ end))
>
>
> 2009/5/5 Ketil Malde <ketil at malde.org>:
>> Thomas Hartman <tphyahoo at gmail.com> writes:
>>
>>> That's slick, but is there some way to use interact twice in the same program?
>>
>> No :-)
>>
>>> t10 =
>>> let f = unlines . takeWhile (not . blank) . lines
>>> in do putStrLn "first time"
>>> interact f
>>> putStrLn "second time"
>>> interact f
>>>
>>> this results in *** Exception: <stdin>: hGetContents: illegal
>>> operation (handle is closed) -}
>>
>> Yes. Interacting uses hGetContents, and hGetContents semi-closes (or
>> fully-closes) the handle. If you do it from GHCi, you only get to run
>> your program once.
>>
>>> I also tried
>>>
>>> t15 =
>>> let grabby = unlines . takeWhile (not . blank) . lines
>>> top = ("first time: " ++) . grabby . ("second time: " ++) . grabby
>>> in interact top
>>
>>> but that didn't work either:
>>> thartman at ubuntu:~/haskell-learning/lazy-n-strict>runghc sequencing.hs
>>> a
>>> first time: second time: a
>>> b
>>> b
>>
>> Well - the input to the leftmost grabby is "second time" prepended to
>> the input from the first, and then you prepend "first time" - so this
>> makes sense.
>>
>> Something like this, perhaps:
>>
>> interact (\s -> let (first,second) = span (not . null) (lines s)
>> in unlines ("first":first++"second":takeWhile (not.null) second))
>>
>>> If someone can explain the subtleties of using interact when you run
>>> out of stdio here, it would be nice to incorporate this into
>>
>> hGetContents - there can only be one.
>>
>> -k
>> --
>> If I haven't seen further, it is by standing in the footprints of giants
>>
>
More information about the Haskell-Cafe
mailing list