2017-12-11 23 views
3

이것은 초보자 용 질문입니다. 내가 파일 목록 및 디렉토리 목록에 파일 및 디렉토리의 목록을 분리한다고 가정 : 하스켈 : 하나의 공통 목록에서 파일 목록과 디렉토리 목록을 만드는 방법

getFilesAndDirs :: [FilePath] -> ([FilePath], [FilePath]) 
getFilesAndDirs paths = 
    let ... 
    in (dirs, files) 

은 아마이 희망 중복, 난 그냥 적당한 키워드를 그리워. 이 작업을 수행하는 올바른 방법은 무엇입니까?

파일과 디렉토리가 임의로 생성됩니다.

+0

'Data.List'에는 요청한 것처럼 보이는'partition' 함수가 있습니다. –

+0

@ MarkSeemann : 여기에있는 문제는 술어가 모나드 ('FilePath -> IO Bool') –

+0

관련 항목이라고 생각합니다. 관련 항목 : https://stackoverflow.com/q/31419429/126014 –

답변

2

Data.List 패키지 술어에 기초 a의 두 목록의 튜플로 a의 목록을 분리 partition :: (a -> Bool) -> [a] -> ([a],[a]) 기능을 갖는다.

그러나 파일이 디렉토리인지 확인하는 경우 isDirectory :: FilePath -> IO Bool을 사용하므로 IO BoolBool과 같지 않기 때문에이를 술어로 직접 사용할 수 없습니다.

그러나 우리는 우리 자신의 partitionM을 작성하고, 하나의 것을 사용할 수 있습니다 : 우리가 수행 할 필요가 있기 때문에, 그것이 IO ([FilePath], [FilePath]) 것을

import System.Directory(isDirectory) 

getFilesAndDirs :: [FilePath] -> IO ([FilePath], [FilePath]) 
getFilesAndDirs = partitionM isDirectory

참고 :

import Data.Bool(bool) 
import Data.Foldable(foldrM) 

partitionM :: (Foldable t, Monad m) => (a -> m Bool) -> t a -> m ([a], [a]) 
partitionM p = foldrM (selectM p) ([],[]) 

selectM :: Monad m => (a -> m Bool) -> a -> ([a], [a]) -> m ([a], [a]) 
selectM p x (ts,fs) = p x >>= return . bool (ts, x:fs) (x:ts,fs) 

우리는 다음처럼 사용할 수 있습니다 I/O를 사용하여 경로가 실제로 디렉토리인지 (파일이 아닌지) 확인하십시오.

+0

대단히 고마워요! –

+0

'selectM'의 결과 타입에 모나드가 누락되지 않았습니까? 또한, 그럴 가치가있는 게으른 패턴 일치입니까? –

+0

@SebastianRedl : 감사합니다. 실제로 가치가 없을 것입니다 :) –

0
module SeparateFiles where 
    import Data.String 
    import System.FilePath.Posix 


    type Path = FilePath 
    getFilesAndDirs :: Path -> [(Path,Path)] 
    getFilesAndDirs path = [splitFileName path] 

FilePath 추출을 파일 및 디렉토리로 분할하려고합니다. 나는 당신에게 아주 짧은 예를 제공합니다.

2

do 표기법을 사용하여 프로그램의 불순한 부분을 조정 한 다음 partition과 같은 기본 제공 (순수) 함수를 사용하여 실제 작업을 수행 할 수 있습니다. 다음은 예입니다 :

module Q47755054 (getFilesAndDirs) where 

import Data.List (partition) 
import Data.Bifunctor (bimap) 
import System.Directory (doesDirectoryExist) 

tagPath :: FilePath -> IO (FilePath, Bool) 
tagPath path = do 
    isDirectory <- doesDirectoryExist path 
    return (path, isDirectory) 

getFilesAndDirs :: [FilePath] -> IO ([FilePath], [FilePath]) 
getFilesAndDirs paths = do 
    taggedPaths <- mapM tagPath paths 
    return $ bimap (fmap fst) (fmap fst) $ partition snd taggedPaths 

공지 이것은 내장 mapM 기능,하지만 인해 do 구문 값의 불순한 목록 (IO [(FilePath, Bool)])와 바인딩 <-를 얻기 위해, taggedPaths 순수처럼 '보이는'사용 값 ([(FilePath, Bool)])이므로 partition에 전달할 수 있습니다.

또한 tagPath은 모듈에서 내 보내지 않은 모듈 수준의 도우미 함수에 불과합니다.