読者です 読者をやめる 読者になる 読者になる

レガシーコード生産ガイド

私に教えられることなら

「すごいHaskellたのしく学ぼう」読み終わった

なんとなくHaskellの楽しさわかった気がする。

次は、モナドや型で、どういう設計をすると楽しいのか調べてみたい。

以下は最後のファイルシステムのコードにMaybeを足したもの。

Maybeを足すときに、Justで包んでいくのが果てしなくめんどうだった。

type FsName = String
type FsData = String

data FsItem = File FsName FsData |
              Folder FsName [FsItem]
              deriving (Show)

showFsItemName :: String -> FsItem -> String
showFsItemName pwd (File fname _)   = pwd ++ "/" ++ fname ++ "\n"
showFsItemName pwd (Folder fname _) = pwd ++ "/" ++ fname ++ "\n"

showFsItem :: String -> FsItem -> String
showFsItem pwd (File fname d) =
  pwd ++ "/" ++ fname ++ "\n"
showFsItem pwd (Folder fname items) =
  let wd = pwd ++ "/" ++ fname
  in  wd ++ "\n" ++
      (foldl (++) "" $ map (showFsItemName "    ") items)

data FsCrumb = FsCrumb FsName [FsItem] [FsItem] deriving (Show)
type FsZipper = (FsItem, [FsCrumb])

absPath :: [FsCrumb] -> String
absPath [] = ""
absPath (FsCrumb name _ _ : bs) = absPath bs ++ "/" ++ name

showFsZipper :: FsZipper -> Maybe String
showFsZipper (item, bs) = Just $ showFsItem (absPath bs) item

x -: f = f x

showSafeFs :: Maybe FsZipper -> IO ()
showSafeFs Nothing = putStrLn "error"
showSafeFs x = putStrLn $ (\(Just x) -> x) $ x >>= showFsZipper

fsUp :: FsZipper -> Maybe FsZipper
fsUp (item, []) = Nothing
fsUp (item, FsCrumb name ls rs : bs) =
  Just (Folder name (ls ++ [item] ++ rs), bs)

nameIs :: FsName -> FsItem -> Bool
nameIs name (Folder folderName _) = name == folderName
nameIs name (File   fileName   _) = name == fileName

fsTo :: FsName -> FsZipper -> Maybe FsZipper
fsTo _ (File _ _, _) = Nothing
fsTo name (Folder fname items, bs) =
  let (ls, item:rs) = break (nameIs name) items
  in  Just (item, FsCrumb fname ls rs : bs)

fsRename :: FsName -> FsZipper -> Maybe FsZipper
fsRename name (Folder fname items, bs) = Just(Folder name items, bs)
fsRename name (File fname d, bs) = Just (File name d, bs)

fsNewFile :: FsItem -> FsZipper -> Maybe FsZipper
fsNewFile _ (File _ _, _) = Nothing
fsNewFile item (Folder na items, bs) = Just (Folder na (item:items), bs)

testDisk :: FsItem
testDisk =
  Folder "root"
  [ File "test1" "contents of test1"
  , File "test2" "contents of test2"
  , Folder "test_folder1" [
    File "test3" "contents of test3"
    ]
  ]

test = do
  putStrLn "*before*"
  showSafeFs $ return (testDisk, [])
  putStrLn "*after*"
  showSafeFs $ return (testDisk, [])
    >>= fsTo "test1" >>= fsRename "hoge"
    >>= fsUp >>= fsNewFile (File "fuo" "fugaa")

広告を非表示にする