2014-11-29 7 views
5

나는 펑의 작동 방식을 이해하려고 노력 중이 야, 그래서 나는 여기에 대해 읽어 : http://learnyouahaskell.com/making-our-own-types-and-typeclasses#the-functor-typeclass하스켈 - 펑

내가지도를 받아 (목록입니다) 값의 합계를 계산하는 기능을 가지고있다.

reduce :: Map String [Int] -> Map String Int 
reduce = fmap sum 

난 정말 fmap가 어떻게 작동하는지 이해하지 못했다는 그래서 나는 그것에 대해 읽고 내 자신의 버전을 만들기 위해 노력했다. Map은 Haskell 라이브러리에서 이미 정의되어 있으므로 실제로 테스트 할 수 없습니다.

이게 맞습니까?

instance Functor (Map k) where 
    fmap f fromList[] = [] 
    fmap f fromList[(k, v): xs] = (f v) fmap xs 
+1

직접 관련 없음,하지만 난 http://adit.io/posts/2013 펑터를 설명하는이 블로그 게시물 매우 명확 발견 : 당신이 정말로 그것을 실험 할 경우, 당신은 newtype를 선언 할 수 있습니다 -04-17-functors, _applicatives, _and_monads_in_pictures.html – chi

+0

멋진데! 고마워, 나는 그것을 조사 할 것이다. –

+2

"Map이 이미 정의 되었기 때문에 테스트 할 수 없습니다"- 코드를 테스트하기 위해'Functor' 인스턴스를 선언 할 필요가 없습니다. 함수를 단독으로 정의하고 기존 함수 (예 :'fmap ')와 충돌하지 않는 이름으로 변경하십시오. –

답변

6

귀하의 예는 도덕적으로 올바른 길을 걷고 있지만 몇 가지 실수가 있습니다. 가장 명확한 점은 fromList이 생성자가 아니기 때문에 fromList ...에서 패턴 매치를 할 수 없다는 것입니다. 실제 생성자는 Data.Map 모듈에서 내 보내지 않으므로 패턴 일치가 전혀 없습니다. 이는 모듈에서 사용 된 내부 트리 표현에 액세스 할 수 없으며 일부 불변성을 손상시킬 수 있음을 보장하기위한 것입니다. 더 양호한 경우는 예를 들어. 이것은 기본적으로 키 - 값 쌍으로 만들어진 연관리스트에 전체지도를 회전

instance Ord k => Functor (Map k) where 
    fmap f m = fromList (map modify (toList m)) 
     where modify (k,v) = (k, fv) 

을 (@gallais 언급으로 제약 Ord kMap에 필요한) 다음 f을 적용하는 모든 값을 변경 한 다음지도를 다시 작성 뒤로. 지도 모듈의 실제 인스턴스가 중간 목록을 통과 할 필요가 없습니다 - 더 간결하게, 그것은이 정말 효율적이지 있음을 유의하십시오

instance Ord k => Functor (Map k) where 
    fmap f = fromList . map (\(k,v) -> (k,f v)) . toList 

과 같이 쓸 수있다.

마지막으로 Map 모듈에서 이미 인스턴스를 제공하므로 인스턴스를 직접 정의 할 수 없습니다. 귀하의 예제에

newtype MyMap k v = MyMap { unMyMap :: Map k v } 

instance Functor (MyMap k) where 
    fmap f = MyMap . fromList . map (\(k,v) -> (k,f v)) . toList . unMyMap 
+2

'Functor' 인스턴스에'Ord k' 제약 조건이 필요할 것입니다. 또한 일화 적으로,'((,) k)'가 그 자체로 하나의 functor라는 점을 감안할 때, 그 정의는 훨씬 더 성공적이 될 수 있습니다. 'fromList '라고 쓸 수 있습니다. fmap (fmap f). toList'. – gallais