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