Totally beginner question

Hi all,

First of all thanks for those organizing this discourse Haskell, as a total beginner on Haskell, it is being useful to have an idea of Haskell community. I don’t know if this is the best place to write a beginner questions, so my apologies if this is more for advanced users.

I am trying to learn it with examples after a basic read of the syntax of the language, but it is being difficult. For example to define a function that creates several directories and returns to the previous path. I was able to make it work like this:

import System.Directory (createDirectory, setCurrentDirectory, getCurrentDirectory)
import Data.List.Split  (splitOn)

main :: IO ()
main = do
  let currentPath = getCurrentDirectory
  let path = splitOn "/" "dirA/subdirB/subsubdirC"
  mapM_ (\x -> createDirectory x >> setCurrentDirectory x) path
  setCurrentDirectory =<< currentPath 

however, when I try to translate this piece of code to a function (before the main) I have a lot of problems. So I guess that probably I don’t understand some key concepts related with let-where-do. Any advice or resource to read would be very appreciated. Thanks!

1 Like

First, normally you don’t change your current working directory when creating some directory structure, you don’t need it (this is true for all programming languages).

If you have trouble writing down the type of a function, you may omit it and let GHC infer it. For example, you could write the function:

import System.FilePath (splitPath, joinPath, (</>))
import System.Directory (getCurrentDirectory, createDirectory)
import Data.List (inits)

createDirectories = do
  cwd <- getCurrentDirectory
  let ps = splitPath (cwd </> "dirA" </> "subdirB" </> "subsubdirC")
  mapM_ (createDirectory . joinPath) (inits ps)

And copy paste it in a .hs file and compile it, GHC will suggest the type. Otherwise, copy it in GHCi (the REPL), and ask the type with :t createDirectories. The type of the function above is IO ().

Note that my a similar function already exists as createDirectoryIfMissing True in System.Directory.

3 Likes

Thanks! I see now that in the implementation I did before used setCurrentDirectory and for this reason I had to use getCurrentDirectory. The difficulty I have is to add the path to be created as an input of the function so a function with type Path -> IO. I guess that it should work as createDirectories path = do ...

Yes, exactly, something like:

createDirectories :: FilePath -> IO ()
createDirectories path = do
  let ps = ["dirA", "subdirB", "subsubdirC"]
  mapM_ (createDirectory . (path </>) . joinPath) (tail (inits ps))

Which is more or less the same as:

createDirectoryIfMissing True (path </> "dirA" </> "subdirB" </> "subsubdirC")
1 Like

Maybe take a look at my tutorial of IO and do notation, it might clear some things up:

2 Likes