Haskell join getHomedirectory string -
i have file strings represent directories. of strings have tilde (~) in it. want join homedirectory (~) of user rest of string. have far:
import data.list (isprefixof) import system.directory (doesdirectoryexist, gethomedirectory) import system.filepath (joinpath) getfullpath s | "~" `isprefixof` s = joinpath [gethomedirectory, tail s] | otherwise = s but following error:
couldn't match type `io filepath' `[char]'expected type: filepath actual type: io filepathin expression: gethomedirectoryin first argument of `joinpath', namely `[gethomedirectory, tail s]'in expression: joinpath i don't know, , can't find, how convert types match , can joined together.
a more idiomatic solution @user2720372 suggests split non-monadic code monadic code. io actions monadic functions in io monad.
if need getfullpath locally makes sense cache home directory:
fullpath homepath s | "~" `isprefixof` s = joinpath [homepath, tail s] | otherwise = s main = homepath <- gethomedirectory let getfullpath = fullpath homepath print $ getfullpath "~/foo" if still need full global getfullpath can implemented this:
getfullpath p = homepath <- gethomedirectory return $ fullpath homepath p and it's considered style keep fullpath , getfullpath separated.
also don't need isprefixof , tail in first place such simple case:
fullpath homepath ('~' : t) = joinpath [homepath, t] fullpath _ s = s if want monolithic getfullpath @user2720372's variant can simplified:
getfullpath s = homedir <- gethomedirectory return $ case s of ('~' : t) -> joinpath [homedir, t] _ -> s note code above refactorings of code preserving wrong behavior: should compare ~ first path component, not first path character. use splitpath system.filepath:
getfullpath s = homedir <- gethomedirectory return $ case splitpath s of ("~" : t) -> joinpath $ homedir : t _ -> s also, do-notation complicated cases. if use do-notation simple two-liners reducible application of fmap/<$>/>>=/>=>/liftm2 or other functions control.monad , control.applicative.
here version:
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 here yet more modular, less readable version:
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 haskell gurus invited rewrite preserve modularity improve readability :)
Comments
Post a Comment