1

I'm trying to figure out how to use the Shelly (Shell.Pipe) library. So far i've got:

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ExtendedDefaultRules #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}
import Control.Applicative
import Data.List(sort)

import Shelly.Pipe
import Data.Text.Lazy as LT

default (LT.Text)

findExt ext = findWhen (pure . hasExt ext)
main = shelly $ verbosely $ do
cd bookPath 
findExt "epub" "."

I can find all the epub files but then I have no idea how to operate on each of the epub file ? For example I want to run ebook-convert command on those file names wrapped by Sh Monad.

Btw: The examples are really scarce on the internet... And it is very confusing that there are two similar libries:Shelly and Shelly.Pipe. The functions inside these two share same name with different Types: In Shelly.Pipe:

find :: FilePath -> Sh FilePath
find = sh1s S.find

In Shelly:

find :: FilePath -> ShIO [FilePath]

Really frustrating !

PS: With the help from John Wiegley I finally got the code working. I post the code below for people who might use it. Pay attention to the use of unpack.

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ExtendedDefaultRules #-}
{-# OPTIONS_GHC -fno-warn-type-defaults #-}

import Control.Applicative
import Data.List(sort)
import Control.Monad
import Shelly
import System.Directory
import Data.Text
import System.FilePath
default (Text)


bookPath = "/dir/to/books"

main = shelly $ verbosely $ do
    fnames <- Shelly.find bookPath  --fnames can not be processed by normal pure String processing functions and need to be "escaped"
    forM_ fnames $ \n-> liftIO $ putStrLn $ ProcessBookFileName $ unpack $ toTextIgnore n --ProcessBookFileName::String->String
Chris Stryczynski
  • 30,145
  • 48
  • 175
  • 286
McBear Holden
  • 5,741
  • 7
  • 33
  • 55
  • I know I'm a beginner but it's really frustrating to have to dig into the source code just to find out how to use this simple function. I wish people can write just a few more examples when they write libries. Haskell itself already got a bad reputation for being difficult(although ALL haskellers claim it easy) – McBear Holden Aug 12 '13 at 13:38
  • 1
    Did you see this tutorial? http://www.linux-magazin.de/Online-Artikel/Shell-scripting-with-type-safety-using-Haskell/ It was linked to in Shelly's readme file. – firefrorefiddle Aug 12 '13 at 13:42
  • @MikeHartl I did. It doesn't help a lot and frankly i think it's a joke teaching people how to write script in Haskell without prior knowledge of Monad – McBear Holden Aug 12 '13 at 13:53

1 Answers1

2

From what I can gather, you don't want to use the Shelly.Pipe module, just the Shelly module. The ShIO monad implements MonadIO, which allows you to execute arbitrary IO actions while inside ShIO. This would let you do something like

convertEpub :: FilePath -> IO ()
convertEpub fname = undefined

main = shelly $ do
    cd "projects/haskell/testing"
    liftIO $ putStrLn "Hello, world!  I'm in Shelly"
    fnames <- find (pure . hasExt "hs") "."
    liftIO $ forM_ fnames $ \fname -> do
        putStrLn $ "Processing file " ++ show fname
        convertEpub fname
bheklilr
  • 53,530
  • 6
  • 107
  • 163
  • 1
    Thank you this helps. I somehow got the idea that Shelly.Pipe is an improved version over Shelly – McBear Holden Aug 12 '13 at 13:55
  • 1
    When I looked at the documentation on Hackage, there was only the `Shelly` module as "public". What it looks like at first glance to me is that `Shelly.Pipe` is a bunch of internal functions, and `Shelly` is the public interface that uses those functions. It will probably be a lot more useful to you to use the `ShIO` monad, since it allows you to still do any kind of IO you like, such as converting files, etc. – bheklilr Aug 12 '13 at 14:05
  • 1
    @osager It actually looks like I was wrong. For whatever reason google didn't bring up the latest version of the Shelly library on hackage, so I was looking at a pretty old version. The documentation says to use the `Sh` monad and the `ShIO` type is being deprecated. The `Sh` monad is still a `MonadIO`, so you can do IO in it with `liftIO`. The documentation still recommends using the `Shelly` module instead of `Shelly.Pipes`. – bheklilr Aug 12 '13 at 15:04
  • thank you for taking the time for verifying this. I'm still struggling in and out of those two Monads – McBear Holden Aug 12 '13 at 15:32
  • There is something missing from your code, especially two functions:unpack and toTextIgnore. – McBear Holden Aug 12 '13 at 22:01
  • 1
    Oh, sorry, I didn't run this code (obviously, since convertEpub is undefined), so I'm not surprised that there are issues. I was more hoping to illustrate how to get the filenames and how to perform IO actions while inside the `Sh` or `ShIO` monads. – bheklilr Aug 12 '13 at 22:07