3

Let's say I want to stream from one file to another file but I want to skip the first n lines of the input file. How do I do this without first collapsing the whole first file using 'fold' ?

import Turtle
main = output "/tmp/b.txt" (f (input "/tmp/a.txt"))

What should 'f' be here to accomplish this ?

ps: I don't have enough reputation to create the 'haskell-turtle' tag.

miguel.negrao
  • 949
  • 5
  • 13
  • I'm not sure a `haskell-turtle` tag is really warranted, so I wouldn't worry about creating it. – Tikhon Jelvis Feb 09 '15 at 23:44
  • 1
    Actually, the `turtle` documentation specifically requested this tag at [the very end](https://hackage.haskell.org/package/turtle-1.0.1/docs/Turtle-Tutorial.html#g:16), but I can remove that request if you think the `haskell` tag is appropriate enough – Gabriella Gonzalez Feb 10 '15 at 00:37
  • @GabrielGonzalez, I think it's probably better to wait for the download numbers to creep up just a bit first. – dfeuer Feb 10 '15 at 01:39

1 Answers1

5

I think this is the correct code:

import Data.IORef
import Turtle

drop :: Int -> Shell a -> Shell a
drop n s = Shell (\(FoldM step begin done) -> do
    ref <- newIORef 0
    let step' x a = do
            n' <- readIORef ref
            writeIORef ref (n' + 1)
            if n' < n then return x else step x a
    foldIO s (FoldM step' begin done) )

... except I'd probably call it something other than drop to avoid clashing with the Prelude.

It's almost identical to Turtle.Prelude.limit (See source code for comparison). The only difference is that I've reversed the then and else clause of the if statement.

If that solves your problem then I'll add it to Turtle.Prelude.

Gabriella Gonzalez
  • 34,863
  • 3
  • 77
  • 135
  • 2
    Do you think its worth adding the `import Data.IORef` to the snippet? I know that Turtle is partly aimed at beginners so I thought it might be worthwhile. – MaxGabriel Feb 10 '15 at 04:26
  • Fixed. I added necessary imports – Gabriella Gonzalez Feb 10 '15 at 05:52
  • That solves it. That's quite a "low level" solution, I wouldn't have come up with it for sure. Might be worth adding it to the library. Btw, in similar way, is it possible to collapse every n lines into one line and pass the resulting lines to the output file in a streaming fashion ? thanks – miguel.negrao Feb 10 '15 at 11:54
  • The main reason it's low level is the need to get exception safety correct. If not for that then I could replace `Shell` with a simpler abstraction like `ListT IO`. – Gabriella Gonzalez Feb 10 '15 at 18:53
  • For your second question, I'd just take the time to understand how `Shell` works. There are some more general ways to do this but they would not be highly reusable. – Gabriella Gonzalez Feb 10 '15 at 18:59
  • 1
    I just want to cast a vote to include this into Prelude.Turtle! By the way, you need to add a "import Prelude hiding (drop)" at the top of the code. Otherwise it works. – Stephan Jan 11 '16 at 10:41