当前位置:  开发笔记 > 开发工具 > 正文

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

如何解决《设计帮助:在Haskell中建模shell体验》经验,为你挑选了0个好方法。

我正在尝试使用Haskell进行虚拟shell体验.我的意思是,我的意思是创建一个程序,当从终端窗口执行时,将您带入一个环境,允许您执行熟悉的命令的子集(例如,cdmkdir)等.

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

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

我写了以下内容

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

输出到以下

?  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 []}]

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

推荐阅读
mobiledu2402851323
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有