<div dir="ltr">I think I'm starting to get the "way of arrows".<div><br></div><div>My implementation was incorrect. I've seen it with the hand made test listed below [1].</div><div>The output of "first arrA" and "first arrB" should be joined together and form a new stream with the length of the shortest output of both ("arrA *** arrB"), and this wasn't happening.</div>
<div><br></div><div>I've found package "streamproc" at Hackage and that gave me some insights.</div><div>Yet I think "streamproc" is also wrong, as it does not buffer the second stream.</div><div>
You can check it at line 58 of SP.hs [3] that it ignores the first element of the pair.</div>
<div>But I didn't write a test to check what is the implication of this, I'll try to do this as a next step into understanding arrows.</div><div><br></div><div>That exercise really helped me!</div><div><br></div>
<div>
My new implementation, wich I think is correct now, is listed below [2].</div><div><br></div><div>Thanks!</div><div><br></div><div>Thiago</div><div><br></div><div><br></div><div>[1]:</div><div><div>inputA :: [String]</div>
<div>inputA = ["a", "b", "hello", "c", "d", "e", "hello", "f", "g", "e", "x"]</div><div><br></div><div>arrA :: SP String String</div>
<div>arrA = Get (\a -> if a == "hello" then (Put a (Put "world" arrA))</div><div> else (Put "unknown" arrA))</div><div><br></div><div>arrB :: SP String String</div>
<div>arrB = Get (\a -> if a == "my" then (Get (\a -> if a == "name" then (Get (\a -> if a == "is" then Get (\a -> Put ("name: " ++ a) arrB)</div><div> else arrB))</div>
<div> else arrB))</div><div> else arrB)</div><div><br></div><div>inputB :: [String]</div><div>inputB = ["a", "b", "my", "name", "is", "thiago", "and", "I", "am", "so", "cool"]</div>
<div><br></div><div>inputAB :: [(String, String)]</div><div>inputAB = zip inputA inputB</div><div><br></div><div>main :: IO ()</div><div>main = let actualOutputB = runSP arrB inputB</div><div> actualOutputB1 = runSP (first arrB) (zip inputB (repeat "a"))</div>
<div> actualOutputA = runSP arrA inputA</div><div> actualOutputA1 = runSP (first arrA) (zip inputA (repeat "a"))</div><div> actualOutputAB = runSP (arrA *** arrB) inputAB</div><div>
in do putStrLn $ "inputAB: " ++ show inputAB</div><div> putStrLn $ "outputA: " ++ show actualOutputA</div><div> putStrLn $ "outputA1: " ++ show actualOutputA1</div>
<div> putStrLn $ "outputB: " ++ show actualOutputB</div><div> putStrLn $ "outputB1: " ++ show actualOutputB1</div><div> putStrLn $ "outputAB: " ++ show actualOutputAB</div>
</div><div><br></div><div><br></div><div><br></div><div>[2]:</div><div><div>module SP where</div><div><br></div><div>import Prelude hiding (id, (.))</div><div>import Control.Category</div><div>import Control.Arrow</div><div>
import Test.QuickCheck</div><div><br></div><div>data SP a b = Put b (SP a b) | Get (a -> SP a b)</div><div><br></div><div>runSP :: SP a b -> [a] -> [b]</div><div>runSP (Put b s) as = b:runSP s as</div><div>runSP (Get k) (a:as) = runSP (k a) as</div>
<div>runSP (Get k) [] = []</div><div><br></div><div>compose :: SP b c -> SP a b -> SP a c</div><div>compose (Put a s) g = Put a (compose s g)</div><div>compose (Get k) (Put a s) = compose (k a) s</div><div>compose f (Get k) = Get (\a -> compose f (k a))</div>
<div><br></div><div>instance Category SP where</div><div> id = arr id</div><div> (.) = compose</div><div><br></div><div>instance Arrow SP where</div><div> arr f = Get (\a -> Put (f a) (arr f))</div><div> first = queued empty empty</div>
<div><br></div><div>queued :: Queue a -> Queue c -> SP a b -> SP (a, c) (b, c)</div><div>queued qa qc (Put a s) = case pop qc of Nothing -> Get (\(a', c) -> Put (a, c) (queued (push a' qa) qc s))</div>
<div> Just (c, qc') -> Put (a, c) (queued qa qc' s)</div><div>queued qa qc (Get k) = case pop qa of Nothing -> Get (\(a, c) -> queued qa (push c qc) (k a))</div><div>
Just (a, qa') -> queued qa' qc (k a)</div><div><br></div><div>data Queue a = Queue [a]</div><div><br></div><div>empty :: Queue a</div><div>empty = Queue []</div><div><br></div>
<div>push :: a -> Queue a -> Queue a</div><div>push a (Queue as) = Queue (a:as)</div><div><br></div><div>pop :: Queue a -> Maybe (a, Queue a)</div><div>pop (Queue []) = Nothing</div><div>pop (Queue (a:as)) = Just (a, Queue as)</div>
<div><br></div><div>delayed :: (a, c) -> SP a b -> SP (a, c) (b, c)</div><div>delayed (a, c) (Put b s) = Put (b, c) (delayed (a, c) s)</div><div>delayed (a, c) (Get k) = firstWithValue (k a) c</div><div><br></div><div>
firstWithValue :: SP a b -> c -> SP (a, c) (b, c)</div><div>firstWithValue (Put a s) c = Put (a, c) (firstWithValue s c)</div><div>firstWithValue (Get k) _ = Get (\(a, c) -> firstWithValue (k a) c)</div><div><br>
</div><div>input :: [(String, String)]</div><div>input = [("a1", "a2"), ("b1", "b2"), ("c1", "c2"), ("d1", "d2")]</div><div><br></div><div>myArrow :: SP (String, String) (String, String)</div>
<div>myArrow = (delay "db1" >>> delay "da1") *** (delay "db2" >>> delay "da2")</div><div><br></div><div>delay :: a -> SP a a</div><div>delay b = Put b (arr id)</div>
<div><br></div><div>inputA :: [String]</div><div>inputA = ["a", "b", "hello", "c", "d", "e", "hello", "f", "g", "e", "x"]</div>
<div><br></div><div>arrA :: SP String String</div><div>arrA = Get (\a -> if a == "hello" then (Put a (Put "world" arrA))</div><div> else (Put "unknown" arrA))</div>
<div><br></div><div>arrB :: SP String String</div><div>arrB = Get (\a -> if a == "my" then (Get (\a -> if a == "name" then (Get (\a -> if a == "is" then Get (\a -> Put ("name: " ++ a) arrB)</div>
<div> else arrB))</div><div> else arrB))</div><div> else arrB)</div>
<div><br></div><div>inputB :: [String]</div><div>inputB = ["a", "b", "my", "name", "is", "thiago", "and", "I", "am", "so", "cool"]</div>
<div><br></div><div>inputAB :: [(String, String)]</div><div>inputAB = zip inputA inputB</div><div><br></div><div>main :: IO ()</div><div>main = let actualOutputB = runSP arrB inputB</div><div> actualOutputB1 = runSP (first arrB) (zip inputB (repeat "a"))</div>
<div> actualOutputA = runSP arrA inputA</div><div> actualOutputA1 = runSP (first arrA) (zip inputA (repeat "a"))</div><div> actualOutputAB = runSP (arrA *** arrB) inputAB</div><div>
in do putStrLn $ "inputAB: " ++ show inputAB</div><div> putStrLn $ "outputA: " ++ show actualOutputA</div><div> putStrLn $ "outputA1: " ++ show actualOutputA1</div>
<div> putStrLn $ "outputB: " ++ show actualOutputB</div><div> putStrLn $ "outputB1: " ++ show actualOutputB1</div><div> putStrLn $ "outputAB: " ++ show actualOutputAB</div>
</div><div><br></div><div><br></div><div><br></div><div>[3]: <a href="https://github.com/peti/streamproc/blob/master/Control/Arrow/SP.hs#L58">https://github.com/peti/streamproc/blob/master/Control/Arrow/SP.hs#L58</a></div>
</div><div class="gmail_extra"><br><br><div class="gmail_quote">2013/10/7 Thiago Negri <span dir="ltr"><<a href="mailto:evohunz@gmail.com" target="_blank">evohunz@gmail.com</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir="ltr">This is my first contact with QuickCheck, but does this test count as a proof that my implementation is correct?<div><br></div><div>QuickCheck shows 100 tests passed.</div><div><br></div><div><div>prop_a xs = runSP (f *** g) xs == runSP (first f >>> swap >>> first g >>> swap) xs</div>
<div> where swap = arr (\(a,b) -> (b,a))</div><div> f = arr (++"a")</div><div> g = arr (++"b")</div></div><div><br></div></div><div class="HOEnZb"><div class="h5"><div class="gmail_extra">
<br><br><div class="gmail_quote">
2013/10/7 Thiago Negri <span dir="ltr"><<a href="mailto:evohunz@gmail.com" target="_blank">evohunz@gmail.com</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div dir="ltr"><div>"<span style="font-family:arial,sans-serif;font-size:13px">On the one hand, indeterminate a's need to be fed in before indeterminate b's get pulled out. On the other hand, the c's need to behave as if they were in a no-op assembly line. One c goes in, the one (and same!) c drops out."</span><div>
<span style="font-family:arial,sans-serif;font-size:13px"><br></span></div></div><div><font face="arial, sans-serif">I agree with "no-op assembly line", but when I'm using `first` on a processor, I want to process the first stream *only*. The second stream should remain as it was not touched, so future processors will receive the same sequence from the second stream.</font></div>
<div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">I mean, I think I need to guarantee that this definition holds:</font></div><div><font face="arial, sans-serif"><br></font></div><div>
<font face="arial, sans-serif">`g *** f` is the same as `first g >>> swap >>> first f >>> swap`</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">If my implementation of `first` uses a real no-op assembly line for `c` (i.e., `arr id`), then I would lose the stream. As you said, I need to buffer the second stream while processing the first one.</font></div>
<div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">Is my line of tought correct?</font></div><div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">I'll try to write some tests to verify this.</font></div>
<div><font face="arial, sans-serif"><br></font></div><div><font face="arial, sans-serif">Thanks!</font></div></div><div class="gmail_extra"><br><br><div class="gmail_quote">2013/10/7 Kim-Ee Yeoh <span dir="ltr"><<a href="mailto:ky3@atamo.com" target="_blank">ky3@atamo.com</a>></span><br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><div><div dir="ltr"><div><div><div><div class="gmail_extra">Hey Thiago,<br><br>First of all, congratulations for reading Hughes! Many of his papers are worth reading and re-reading for both beginners and experts alike.<div>
<br><br><div class="gmail_quote">
On Tue, Oct 8, 2013 at 12:05 AM, Thiago Negri <span dir="ltr"><<a href="mailto:evohunz@gmail.com" target="_blank">evohunz@gmail.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
Exercise 2 (section 2.5) is asking to create a Stream Processor that can map more than one output per input (e.g. 3 outcomes for a single consume of the stream).</blockquote></div><br></div>Given<div><br><br>> data SP a b = Put b (SP a b) | Get (a -> SP a b)<br>
<br></div></div><div>it's easy to see that it's not just about more than one output per input. It's about n pieces of input producing m pieces of output, where (n,m) may even -- and probably does -- depend on previous inputs!<br>
<br></div><div>The exercise asks for an implementation of the following Arrow instance:<br></div><div><br></div>> first :: arr a b -> arr (a,c) (b,c)<br><br></div>which, specialized to our case, is just SP a b -> SP (a,c) (b,c).<br>
<br></div>It should now be apparent what the 'trickiness' is. On the one hand, indeterminate a's need to be fed in before indeterminate b's get pulled out. On the other hand, the c's need to behave as if they were in a no-op assembly line. One c goes in, the one (and same!) c drops out.<br>
<br></div>So one way to look at this is as a buffering problem.<br><div><div><div><div><br>At this point, I'd encourage you to think of some quickcheck tests you can write to convince yourself whether you have a right implementation or not.<br>
</div><div><br></div><div>Your main function doesn't seem adequate for the task.<span><font color="#888888"><br><br>-- Kim-Ee</font></span></div><div><div class="gmail_extra">
</div></div></div></div></div></div>
<br></div></div>_______________________________________________<br>
Beginners mailing list<br>
<a href="mailto:Beginners@haskell.org" target="_blank">Beginners@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/beginners" target="_blank">http://www.haskell.org/mailman/listinfo/beginners</a><br>
<br></blockquote></div><br></div>
</blockquote></div><br></div>
</div></div></blockquote></div><br></div>