Design Assistance: Haskell Shell Modeling

I am trying to use a virtual shell using Haskell. I mean, what I mean is to create a program that when executed from a terminal window turns you into an environment that allows you to execute a subset of familiar commands (like cd and mkdir ) among others.

The file system will be completely virtual, since it does not touch anything on the disk.

My initial sketch (below) seems awkward, so much so that drawing up the MWE was a drag and drop, I’m very unaccustomed to presenting data structures and would like some guidance on how to turn this experience around. Any help program with accessible source code will be useful, like any advice or line of thought.

I wrote the following

 import qualified Data.Map as Map import qualified Data.Either as Either type Name = String type Content = String type Error = String data DiskEntry = File Name Content | Directory {name :: Name , entries :: Map.Map String DiskEntry } deriving (Show) -- | The 'mkdir' function creates a new directory inside the given -- directory. Attempts to create a 'DiskEntry' with the name 'name' -- inside the given 'directory'. If an entry with that name already -- exists an error is returned. If such an entry does not exist -- then it is added to the destination 'DiskEntry' and is returned -- as part of a tuple, where the left entry is the old (modified) 'DiskEntry' -- and the right entry is the newly created 'DiskEntry'. mkdir :: Name -> DiskEntry -> Either Error (DiskEntry, DiskEntry) mkdir entryName destination = do if Map.member entryName $ entries destination then do Left $ "mkdir: cannot create directory '" ++ entryName ++ "': File exists" else do let newDirectory = Directory entryName Map.empty d = addToEntries entryName newDirectory destination in Right (d, newDirectory) addToEntries :: Name -> DiskEntry -> DiskEntry -> DiskEntry addToEntries newEntryName newEntry destination = do let updatedEntries = Map.insert newEntryName newEntry (entries destination) d = Directory (name destination) updatedEntries in d ls :: DiskEntry -> [DiskEntry] ls currentDirectory = map snd $ Map.toList $ entries currentDirectory root :: DiskEntry root = Directory "/" Map.empty main :: IO () main = do -- Pretend that we have several "Either Error (DiskEntry, DiskEntry)" -- We know that we have Right values, so get the first result from -- that and extract the first element in the tuple which is the -- newly modified "root" directory. let old = fst $ Either.rights [mkdir "bin" root] !! 0 putStrLn "Connected. Take this shell, and may it serve you well." putStrLn "I will not you create anything yet, but there is a" putStrLn "directory, \"/\" which you are currently in." putStrLn "The `ls` command should let you see what else is there" putStrLn "I will do that for you now" putStrLn $ show $ ls old 

which is displayed next

 āžœ ls-adventures git:(master) āœ— ghci main.hs GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help [1 of 1] Compiling Main ( main.hs, interpreted ) Ok, modules loaded: Main. *Main> :main Connected. Take this shell, and may it serve you well. I will not you create anything yet, but there is a directory, "/" which you are currently in. The `ls` command should let you see what else is there I will do that for you now [Directory {name = "bin", entries = fromList []}] 

I am very unhappy with the means for updating directories, I would much prefer my function to be able to update the link directory in place. Is this possible through something like a state monad? Oh, and I guess the code looks awful, like in non-idiomatic Haskell?

+7
shell haskell
source share

No one has answered this question yet.

See related questions:

3513
Check if directory exists in shell script
1554
What does "2> & 1" mean in a shell?
1324
How do I request Yes / No / Cancel input in a Linux shell script?
1147
How to use SSH to run a shell script on a remote computer?
1010
Invoking shell commands from Ruby
994
Date date YYYY-MM-DD in shell script
757
Getting started with Haskell
755
Shell command to sum integers, one per line?
748
Check for an input argument in a bash shell script
534
Large-scale design in Haskell?

All Articles