Haskell加入getHomedirectory字符串

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)

我不知道,我找不到,如何转换类型,使它们匹配,并可以连接在一起.

npo*_*cop 8

比@ 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)

它被认为是保持fullPathgetFullPath分离的好方式.

对于这样一个简单的案例,你也不需要isPrefixOftail首先:

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.MonadControl.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大师重写它以保持模块化但提高可读性:)