Arj*_*tra 2 string haskell filepath
我有一个包含代表目录的字符串的文件.其中一些字符串中有一个波浪号(〜).我想将用户的homedirectory(〜)加入到字符串的其余部分.到目前为止我所拥有的:
import Data.List (isPrefixOf)
import System.Directory (doesDirectoryExist, getHomeDirectory)
import System.FilePath (joinPath)
getFullPath s
| "~" `isPrefixOf` s = joinPath [getHomeDirectory, tail s]
| otherwise = s
Run Code Online (Sandbox Code Playgroud)
但是我收到以下错误:
Couldn't match type `IO FilePath' with `[Char]'Expected type: FilePath Actual type: IO FilePathIn the expression: getHomeDirectoryIn the first argument of `joinPath', namely `[getHomeDirectory, tail s]'In the expression: joinPath
Run Code Online (Sandbox Code Playgroud)
我不知道,我找不到,如何转换类型,使它们匹配,并可以连接在一起.
比@ user2720372建议的更惯用的解决方案是从monadic代码中分离非monadic代码.IO动作是IOmonad 中的monadic函数.
如果你只需要getFullPath本地,那么缓存主目录是有意义的:
fullPath homePath s
| "~" `isPrefixOf` s = joinPath [homePath, tail s]
| otherwise = s
main = do
homePath <- getHomeDirectory
let getFullPath = fullPath homePath
print $ getFullPath "~/foo"
Run Code Online (Sandbox Code Playgroud)
如果你仍然需要全局全局,getFullPath那么它可以像这样实现:
getFullPath p = do
homePath <- getHomeDirectory
return $ fullPath homePath p
Run Code Online (Sandbox Code Playgroud)
它被认为是保持fullPath和getFullPath分离的好方式.
对于这样一个简单的案例,你也不需要isPrefixOf和tail首先:
fullPath homePath ('~' : t) = joinPath [homePath, t]
fullPath _ s = s
Run Code Online (Sandbox Code Playgroud)
如果你只想要一个单片,getFullPath那么@ user2720372的变体可以简化:
getFullPath s = do
homeDir <- getHomeDirectory
return $ case s of
('~' : t) -> joinPath [homeDir, t]
_ -> s
Run Code Online (Sandbox Code Playgroud)
请注意,上面的代码只是重构代码,保留了错误的行为:您应该~与第一个路径组件进行比较,而不是与第一个路径字符进行比较.使用splitPath来自System.FilePath:
getFullPath s = do
homeDir <- getHomeDirectory
return $ case splitPath s of
("~" : t) -> joinPath $ homeDir : t
_ -> s
Run Code Online (Sandbox Code Playgroud)
此外,符号仅适用于复杂的情况.如果您使用做的符号,用于简单的两衬那么几乎可以肯定归结为一个应用程序fmap/ <$>/ >>=/ >=>/ liftM2或其他功能Control.Monad和Control.Applicative.
这是另一个版本:
import Control.Applicative ((<$>))
import System.Directory (getHomeDirectory)
import System.FilePath (joinPath, splitPath)
getFullPath s = case splitPath s of
"~/" : t -> joinPath . (: t) <$> getHomeDirectory
_ -> return s
main = getFullPath "~/foo" >>= print
Run Code Online (Sandbox Code Playgroud)
这是另一个更模块化但不太可读的版本:
import Control.Applicative ((<$>), (<*>))
import System.Directory (getHomeDirectory)
import System.FilePath (joinPath, splitPath)
main = getFullPath "~/foo" >>= print
withPathComponents f = joinPath . f . splitPath
replaceHome p ("~/" : t) = p : t
replaceHome _ s = s
getFullPath path = withPathComponents . replaceHome <$> getHomeDirectory <*> return path
Run Code Online (Sandbox Code Playgroud)
邀请Haskell大师重写它以保持模块化但提高可读性:)