设计帮助:在Haskell中建模shell体验

时间:2015-12-23 18:29:35

标签: shell haskell

我正在尝试使用Haskell进行虚拟shell体验。我的意思是,我的意思是创建一个程序,当从终端窗口执行时,将您带入一个允许您执行熟悉命令子集的环境(例如,cd和{{1除其他外。

文件系统将完全是虚拟的,因为它不会触及磁盘上的任何内容。

我的初始草图(下图)感觉很笨,事实上,组成一个MWE是一个拖累,我非常不习惯在功能上表示数据结构,并希望得到一些关于如何扭转这种体验的指针。任何有可用源代码的参考程序都会有所帮助,就像任何提示或思路一样。

我写了以下内容

mkdir

输出到以下

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

我对更新目录的方法非常不满意,我更希望我的函数能够在适当的位置更新引用的目标目录。这可能通过State Monad这样的东西来实现吗?哦,我认为代码看起来很可怕,就像非惯用的Haskell一样?

0 个答案:

没有答案