함수형 프로그래밍에서 펑터 란 무엇입니까?


224

함수형 프로그래밍에 대한 다양한 기사를 읽는 동안 'Functor'라는 용어를 몇 번 보았지만 저자는 일반적으로 독자가 이미 그 용어를 이해한다고 가정합니다. 웹을 둘러 보면 지나치게 기술적 인 설명 ( Wikipedia 기사 참조 ) 또는 매우 모호한 설명 (이 기관 교육용 웹 사이트의 Functors 섹션 참조 )이 제공되었습니다.

누군가가 용어를 친절하게 정의하고, 그 사용법을 설명하고, 펑터가 어떻게 만들어지고 사용되는지에 대한 예를 제공 할 수 있습니까?

편집 : 나는 용어 ​​뒤에 이론에 관심이 있지만 개념의 구현과 실제 사용에 대한 것보다 이론에 덜 관심이 있습니다.

편집 2 : 몇 가지 교차 용어가 진행되는 것처럼 보입니다. 저는 C ++의 함수 객체가 아닌 함수형 프로그래밍의 Functors를 언급하고 있습니다.




성층권 용어와 개념 뒤에있는 이론보다 실제 구현과 사용에 더 관심이 있다면, 하나의 라이너 만 있으면됩니다. functor는 "맵"기능을 노출합니다.
Richard Gomes

@RichardGomes IMHO 나는 그것이 functor의 역할을 단순한 Java와 같은 인터페이스로 줄인다고 생각합니다. functor는 물건을 변형시키고 기존 유형 (Haskell)에서 새로운 유형을 작성합니다. 즉 유형도 매핑됩니다. fmap함수를 매핑합니다. 두 가지 종류의 매핑이 있습니다. 그런 것들을 보는 방식은 범주 이론 (더 일반적인)을 이해하는 데 도움이 될 것입니다. Haskell의 모든 범주 이론 (functor, monads, ...)에 도움이되는 기본 범주 이론을 이해하는 것이 흥미 롭습니다.
Ludovic Kuty

@VladtheImpala 블로그 게시물은 환상적이지만 많은 도움이 되더라도 functor가 다른 유형을 빌드 (매핑)한다는 점을 명심하고 싶습니다. 나는 특히 모나드 에서 "A functor F는 각 유형 T를 가져 와서 새로운 유형 FT에 매핑한다"라는 문장을 좋아한다 . IMHO 그것은 이런 것들을 보는 것이 실용적 임에도 불구하고 가치에 대한 맥락 (상자)이 아니다 (Haskell PoV vs 카테고리 이론 PoV?)
Ludovic Kuty

답변:


273

"functor"라는 단어는 범주 이론에서 나왔는데, 이는 매우 일반적이고 매우 추상적 인 수학 분기입니다. 함수형 언어 디자이너는 적어도 두 가지 방법으로 빌려왔다.

  • ML 언어 언어에서 functor는 하나 이상의 다른 모듈을 매개 변수로 사용하는 모듈입니다. 고급 기능으로 간주되며 대부분의 초보 프로그래머에게는 어려움이 있습니다.

    구현 및 실제 사용의 예로서, 선호하는 형태의 균형 이진 검색 트리를 한번에 functor로 정의 할 수 있으며, 다음과 같은 기능을 제공하는 모듈로 사용할 수 있습니다.

    • 이진 트리에서 사용될 키의 유형

    • 키의 총 주문 기능

    이 작업을 수행하면 동일한 균형 이진 트리 구현을 영원히 사용할 수 있습니다. (트리에 저장된 값의 유형은 일반적으로 다형성으로 남습니다. 트리는 값을 복사하는 것 이외의 값을 볼 필요가 없지만 트리는 반드시 키를 비교할 수 있어야하며 비교 기능을 가져옵니다. functor의 매개 변수)

    ML functors의 또 다른 응용은 계층화 된 네트워크 프로토콜 입니다. CMU Fox 그룹의 링크는 정말 훌륭한 논문입니다. 또한 functors를 사용하여 간단한 계층 유형 (IP 또는 직접 이더넷을 통해)에 더 복잡한 프로토콜 계층 (TCP와 같은)을 구축하는 방법을 보여줍니다. 각 레이어는 그 아래 레이어를 매개 변수로 사용하는 functor로 구현됩니다. 소프트웨어의 구조는 실제로 프로그래머의 마음에만 존재하는 계층과 달리 사람들이 문제에 대해 생각하는 방식을 반영합니다. 이 작품이 출판 된 1994 년에는 큰 일이었습니다.

    ML functors의 실제 사례에 대해서는 ML Module Mania 라는 논문 이 있습니다. ML 모듈 시스템 (다른 종류의 모듈과 비교)에 대한 훌륭하고 명료 한 설명은 Xavier Leroy의 화려한 1994 POPL 논문 매니페스트 유형, 모듈 및 개별 컴파일 의 처음 몇 페이지를 읽으십시오 .

  • 하스켈에서, 일부 관련 순수 함수형 언어에서, FunctorA는 유형 클래스 . 형식이 특정 동작에 특정 동작을 제공 할 때 형식은 형식 클래스 (또는 기술적으로는 형식 클래스의 인스턴스 임)에 속합니다. 컬렉션과 같은 특정 동작이 있는 유형 T은 클래스에 속할 수 있습니다 Functor.

    • 유형 T은 다른 유형에 대해 매개 변수화되며 이는 콜렉션의 요소 유형으로 생각해야합니다. 전체 컬렉션의 유형은 다음과 같이이다 T Int, T String, T Bool,는 각각 정수, 문자열 또는 부울을 포함하는 경우. 요소의 형태를 알 수없는 경우, 그것은으로 기록 된 유형 매개 변수 a 처럼 T a.

      예를 들어 목록 (0 개 이상의 유형의 요소 a), Maybe유형 (0 또는 하나의 유형 a의 요소), 유형 의 요소 집합 a, 유형 의 요소 배열 a, 유형의 값을 포함하는 모든 종류의 검색 트리 a등이 있습니다. 생각할 수 있습니다.

    • T만족해야 할 또 다른 속성 은 유형 a -> b의 함수 (요소의 함수)가있는 경우 해당 함수를 가져 와서 콜렉션에서 관련 함수를 생성 할 수 있어야한다는 것입니다. 유형 클래스의 fmap모든 유형이 공유 하는 연산자 로이를 수행합니다 Functor. 당신이 함수 그래서 만약 운영자는 실제로 오버로드 even유형을 Int -> Bool한 후,

      fmap even

      많은 훌륭한 일을 할 수있는 오버로드 된 함수입니다 :

      • 정수 목록을 부울 목록으로 변환

      • 정수 트리를 부울 트리로 변환

      • 변환 NothingNothingJust 7Just False

      Haskell에서이 속성은 다음 유형을 나타냅니다 fmap.

      fmap :: (Functor t) => (a -> b) -> t a -> t b

      여기서 우리는 작은 클래스를 갖게 t되었습니다 Functor. "클래스의 모든 유형"을 의미합니다 .

    간단히 이야기하자면, Haskell 에서 functor는 요소에 함수가 제공되면 collections에 함수를 제공하는 일종의 fmap컬렉션 입니다. 당신이 상상할 수 있듯이, 이것은 널리 재사용 할 수있는 아이디어이므로 하스켈의 표준 라이브러리의 일부로 축복을받습니다.

평소와 같이 사람들은 새롭고 유용한 추상화를 계속해서 개발하고 있으며, 응용 기능 을 살펴보고 싶을 때 가장 유용한 참고 자료는 Conor McBride와 Ross Paterson의 Applicative Programming with Effects 라는 논문 입니다.


7
ML functors와 Haskell functors를 모두 이해하지만 이들을 함께 연관시킬 통찰력이 부족합니다. 카테고리 이론적 의미에서이 둘의 관계는 무엇입니까?
웨이 후

6
@Wei Hu : 카테고리 이론은 전혀 이해가되지 않았습니다. 내가 말할 수있는 가장 좋은 것은 세 가지 개념 모두 매핑과 관련이 있다는 것입니다.
노먼 램지

16
Haskell 위키 ( en.wikibooks.org/wiki/Haskell/Category_theory) 에 따르면 카테고리는 객체와 형태 (함수)의 모음입니다. . 펑 터는 한 범주의 개체와 형태를 다른 범주의 개체와 형태로 매핑하는 기능입니다. 그게 내가 이해하는 방법입니다. 내가 아직 이해하지 못한 프로그래밍에 대한 의미.
paul

5
@ norman-ramsey, Lawvere와 Schanuel의 개념적 수학을 보셨습니까? 나는 그 지역에 대한 완전한 초보자이지만 책은 눈에 잘 띄고 읽을 수 있고 즐겁습니다. (당신의 설명을 좋아했습니다.)
Ram Rajamony

2
then you have to be able to take that function and product a related function on collectionsproduce대신에 의미 했습니까 product?
problemofficer

64

여기에 다른 답변이 완료되었지만 functor 의 FP 사용에 대한 다른 설명을 시도해 보겠습니다 . 이것을 유추로 보자.

펑터 타입의 컨테이너 에서지도하는 기능을 실시한다는 → b는 입력의 산출 컨테이너 B를 .

C ++에서 abstracted function-pointer 사용과 달리 여기서 functor는 함수가 아닙니다 . 오히려, 함수를 받을 때 일관되게 동작 하는 것 입니다.


3
b 유형의 컨테이너는 "입력 컨테이너와 동일한 종류의 컨테이너이지만 이제 b로 채워짐"을 의미합니다. 따라서 바나나 목록 이 있고 바나나를 가져와 과일 샐러드를 출력하는 함수를 매핑 하면 과일 샐러드 목록이 생깁니다. 마찬가지로 바나나 나무 가 있고 같은 기능 을 매핑 하면 사과 나무 가 생깁니다. 기타 트리리스트 는 여기에 두 개의 Functors입니다.
Qqwy

3
"펑터 (functor)는 함수를받을 때 유형 a의 컨테이너입니다."-실제로 다른 방법입니다.-함수 (형태)는 펑터에 종속되어 다른 형태로 매핑됩니다.
Dmitri Zaitsev

38

크게 관련이없는 세 가지 다른 의미가 있습니다!

  • Ocaml에서는 매개 변수화 된 모듈입니다. 매뉴얼을 참조하십시오 . 나는 그것들을 이해하는 가장 좋은 방법은 예를 들면 다음과 같다고 생각합니다. (빠르게 작성하면 버그가있을 수 있습니다)

    module type Order = sig
        type t
        val compare: t -> t -> bool
    end;;
    
    
    module Integers = struct
        type t = int
        let compare x y = x > y
    end;;
    
    module ReverseOrder = functor (X: Order) -> struct
        type t = X.t
        let compare x y = X.compare y x
    end;;
    
    (* We can order reversely *)
    module K = ReverseOrder (Integers);;
    Integers.compare 3 4;;   (* this is false *)
    K.compare 3 4;;          (* this is true *)
    
    module LexicographicOrder = functor (X: Order) -> 
      functor (Y: Order) -> struct
        type t = X.t * Y.t
        let compare (a,b) (c,d) = if X.compare a c then true
                             else if X.compare c a then false
                             else Y.compare b d
    end;;
    
    (* compare lexicographically *)
    module X = LexicographicOrder (Integers) (Integers);;
    X.compare (2,3) (4,5);;
    
    module LinearSearch = functor (X: Order) -> struct
        type t = X.t array
        let find x k = 0 (* some boring code *)
    end;;
    
    module BinarySearch = functor (X: Order) -> struct
        type t = X.t array
        let find x k = 0 (* some boring code *)
    end;;
    
    (* linear search over arrays of integers *)
    module LS = LinearSearch (Integers);;
    LS.find [|1;2;3] 2;;
    (* binary search over arrays of pairs of integers, 
       sorted lexicographically *)
    module BS = BinarySearch (LexicographicOrder (Integers) (Integers));;
    BS.find [|(2,3);(4,5)|] (2,3);;

이제 가능한 많은 주문을 신속하게 추가 할 수 있으며, 새로운 주문을 작성하는 방법, 이진 또는 선형 검색을 쉽게 수행 할 수 있습니다. 일반 프로그래밍 FTW.

  • Haskell과 같은 함수형 프로그래밍 언어에서 "매핑"될 수있는 일부 유형 생성자 (목록, 세트와 같은 매개 변수화 된 유형)를 의미합니다. 정확하게 말하면 펑터에는가 f장착되어 (a -> b) -> (f a -> f b)있습니다. 이것은 범주 이론의 기원을 가지고 있습니다. 링크 된 Wikipedia 기사가이 사용법입니다.

    class Functor f where
        fmap :: (a -> b) -> (f a -> f b)
    
    instance Functor [] where      -- lists are a functor
        fmap = map
    
    instance Functor Maybe where   -- Maybe is option in Haskell
        fmap f (Just x) = Just (f x)
        fmap f Nothing = Nothing
    
    fmap (+1) [2,3,4]   -- this is [3,4,5]
    fmap (+1) (Just 5)  -- this is Just 6
    fmap (+1) Nothing   -- this is Nothing

그래서 이것은 특별한 종류의 타입 생성자이며 Ocaml의 펑터와는 거의 관련이 없습니다!

  • 명령형 언어에서는 함수를 가리키는 포인터입니다.

이 주석의 마지막 3 줄에있는 <q> map </ q>이 실제로 <q> fmap </ q>이 아니어야합니까?
imz-Ivan Zakharyaschev

1
나는 항상 functors가 컨테이너라는 것을 읽었지만 이것은 단순한 단순화가 아닙니다. 당신의 대답은 마침내 누락 된 링크를 제공했습니다 : Functors는 매개 변수화 유형 (유형 생성자)에 대한 유형 클래스 (유형 제약 조건)입니다. 그렇게 간단합니다!

16

OCaml에서는 매개 변수화 된 모듈입니다.

C ++을 알고 있다면 OCaml functor를 템플릿으로 생각하십시오. C ++에는 클래스 템플릿 만 있으며 펑 터는 모듈 규모로 작동합니다.

functor의 예는 Map.Make입니다. module StringMap = Map.Make (String);;문자열 키 맵과 함께 작동하는 맵 모듈을 빌드합니다.

다형성만으로 StringMap과 같은 것을 얻을 수 없었습니다. 키에 대해 몇 가지 가정을해야합니다. 문자열 모듈에는 전체적으로 정렬 된 문자열 유형에 대한 연산 (비교 등)이 포함되며 functor는 문자열 모듈에 포함 된 연산과 연결됩니다. 객체 지향 프로그래밍과 비슷한 것을 할 수는 있지만 메소드 간접 오버 헤드가 있습니다.


나는 ocaml 웹 사이트에서 그것을 얻었지만 매개 변수가있는 모듈의 사용이 무엇인지 이해할 수 없습니다.
Erik Forbes

4
@Kornel 그래, 내가 설명한 것은 OCaml 개념이다. 다른 개념은 "기능적 가치"일 뿐이며, FP에서는 특별한 것이 아닙니다. @Erik 나는 약간 확장했지만 참조 문서는로드가 느립니다.
Tobu

13

당신은 꽤 좋은 답변을 받았습니다. 나는 투구 할 것이다 :

수학적 의미에서 펑 터는 대수에서 특별한 종류의 기능입니다. 대수를 다른 대수에 매핑하는 최소한의 함수입니다. "최소 성"은 functor 법률에 의해 표현됩니다.

이것을 보는 두 가지 방법이 있습니다. 예를 들어,리스트는 어떤 유형의 함수입니다. 즉, 'a'유형에 대한 대수가 주어지면 'a'유형의 항목을 포함하는 호환되는 대수 목록을 생성 할 수 있습니다. (예를 들어, 요소를 포함하는 단일 목록으로 요소를 가져 오는 맵 : f (a) = [a]) 다시, 호환성 개념은 functor 법률에 의해 표현됩니다.

다른 한편으로, 펑터 (functor) f "a"는 타입 a (즉, fa는 펑터 f를 타입 a의 대수에 적용한 결과 임)이며 g에서 함수입니다 : a-> b, 우리는 계산할 수 있습니다 fa에 f를 매핑하는 새로운 functor F = (fmap g) b. 간단히 말해, fmap은 "functor parts"를 "functor parts"에 매핑하는 F의 일부이고 g는 "algebra parts"를 "algebra parts"에 매핑하는 기능의 일부입니다. 함수, functor가 필요하고 일단 완료되면 functor이기도합니다.

다른 언어는 다른 개념의 펑터를 사용하고있는 것처럼 보이지만 그렇지 않습니다. 그들은 단순히 다른 대수에 함수를 사용하고 있습니다. OCamls에는 대수 모듈이 있으며 해당 대수를 통해 함수를 사용하면 새로운 선언을 "호환 가능한"방식으로 모듈에 첨부 할 수 있습니다.

Haskell functor는 타입 클래스가 아닙니다. 유형 클래스를 충족시키는 자유 변수가있는 데이터 유형입니다. 자유 변수가없는 데이터 유형의 내장을 기꺼이 파고 싶다면 데이터 유형을 기본 대수의 함수로 해석 할 수 있습니다. 예를 들면 다음과 같습니다.

데이터 F = F Int

Int 클래스에 동형입니다. 따라서 값 생성자 인 F는 Int를 동등한 대수 인 F Int에 매핑하는 함수입니다. functor입니다. 반면에, 당신은 여기서 무료로 fmap을 얻지 못합니다. 이것이 패턴 일치를위한 것입니다.

펑 터는 대수적으로 요소를 대수적으로 호환되는 방식으로 "첨부"하는 데 유용합니다.


8

이 질문에 대한 가장 좋은 답변은 Brent Yorgey의 "Typeclassopedia"에 있습니다.

Monad Reader의 이번 호에는 functor가 무엇인지에 대한 정확한 정의와 다른 개념 및 다이어그램에 대한 많은 정의가 포함되어 있습니다. (모노 이드, 어플리 케이 티브, 모나드 및 기타 개념은 펑터와 관련하여 설명되고 보입니다).

http://haskell.org/sitewiki/images/8/85/TMR-Issue13.pdf

Functor 용 Typeclassopedia에서 발췌 : "간단한 직감은 Functor가 컨테이너의 모든 요소에 균일하게 기능을 적용하는 기능과 함께 일종의"컨테이너 "를 나타냅니다."

그러나 실제로 전체 classclasspedia는 놀랍도록 쉬운 권장 사항입니다. 어떤 식 으로든 주어진 클래스 또는 클래스가 주어진 동작이나 기능에 대한 어휘를 제공한다는 점에서 객체의 디자인 패턴과 평행하게 표시되는 것을 볼 수 있습니다.

건배


7

O'Reilly OCaml 책에는 Inria의 웹 사이트에있는 좋은 예가 있습니다 (이 글은 불행히도 다운되었습니다). 이 책에서 caltech가 사용한 매우 유사한 예를 찾았습니다 : OCaml 소개 (pdf 링크) . 관련 섹션은 펑터에 관한 장입니다 (도서의 139 페이지, PDF의 149 페이지).

이 책에는 목록으로 구성된 데이터 구조를 작성하고 요소를 추가하고 요소가 목록에 있는지 판별하고 요소를 찾는 기능을하는 MakeSet 기능이 있습니다. 세트에 있는지 여부를 결정하는 데 사용되는 비교 함수가 매개 변수화되었습니다 (이는 MakeSet을 모듈 대신 functor로 만드는 이유입니다).

또한 대소 문자를 구분하지 않는 문자열 비교를 수행하기 위해 비교 기능을 구현하는 모듈이 있습니다.

functor와 비교를 구현하는 모듈을 사용하면 한 줄에 새 모듈을 만들 수 있습니다.

module SSet = MakeSet(StringCaseEqual);;

대소 문자를 구분하지 않는 비교를 사용하는 세트 데이터 구조에 대한 모듈을 작성합니다. 대 / 소문자를 구분하는 비교를 사용하는 집합을 만들려면 새 데이터 구조 모듈 대신 새 비교 모듈을 구현하면됩니다.

Tobu는 functors를 C ++의 템플릿과 비교했는데 꽤 적절하다고 생각합니다.


6

다른 답변과 내가 지금 게시 할 내용을 감안할 때, 그것은 다소 과부하 된 단어이지만 어쨌든 ...

Haskell에서 'functor'라는 단어의 의미에 대한 힌트를 얻으려면 GHCi에 문의하십시오.

Prelude> :info Functor
class Functor f where
  fmap :: forall a b. (a -> b) -> f a -> f b
  (GHC.Base.<$) :: forall a b. a -> f b -> f a
        -- Defined in GHC.Base
instance Functor Maybe -- Defined in Data.Maybe
instance Functor [] -- Defined in GHC.Base
instance Functor IO -- Defined in GHC.Base

따라서 기본적으로 Haskell의 functor는 매핑 할 수있는 것입니다. 또 다른 방법은 functor는 주어진 함수를 사용하여 포함 된 값을 변환하도록 요청 될 수있는 컨테이너로 간주 될 수있는 것입니다. 그러므로,리스트에 대해, fmap일치와 map, 대 Maybe, fmap f (Just x) = Just (f x), fmap f Nothing = Nothing

은 Functor typeclass 항 및 섹션 펑, 실용적 펑과 Monoids하스켈 아주 좋은 당신을 알아은 이 특정 개념이 유용한 경우의 예를 제공합니다. (요약 : 많은 장소! :-))

모든 모나드는 functor로 취급 될 수 있으며, Craig Stuntz가 지적한 것처럼 가장 자주 사용되는 funct는 모나드 인 경향이 있습니다. 그것을 모나드로 만드는 데 어려움을 겪지 않고. (의 경우의 예 ZipList에서 Control.Applicative의 언급 상기 페이지 중 하나 ).


5

다음 은 프로그래밍 POV의 펑터에 대한 기사 와 프로그래밍 언어로 표시되는 방법에 대한 설명 입니다.

functor의 실제 사용은 모나드에 있으며 모나드에 대한 많은 자습서를 찾을 수 있습니다.


1
"실용적으로 functor를 사용하는 것은 모나드에 있습니다." 모든 모나드는 펑터이지만 비-모나드 펑터에는 많은 용도가 있습니다.
amindfv

1
펑터를 사용하기 위해 모나드를 연구하는 것은 롤스가 식료품을 사러가는 비용을 절약하는 것과 같습니다.
Marco Faustinelli

5

인기 투표 답변에 대한 사용자 Wei Wei 는 다음과 같이 묻습니다.

ML functors와 Haskell functors를 모두 이해하지만 이들을 함께 연관시킬 통찰력이 부족합니다. 카테고리 이론적 의미에서이 둘의 관계는 무엇입니까?

참고 : ML을 모르므로 관련된 실수를 용서하고 수정하십시오.

처음에는 우리가 모두 '범주'와 '펑터'의 정의에 익숙하다고 가정하자.

간단한 답변은 "Haskell functors"는 (엔도) functors F : Hask -> Hask이고 "ML-functors"는 functors G : ML -> ML'입니다.

여기, HaskHaskell 유형과 기능 사이의 범주가 유사 ML하며 ML'ML 구조로 정의 된 범주입니다.

참고 : 카테고리 를 만드는 데 기술적 인 문제Hask있지만 그 주변에는 방법이 있습니다.

범주 이론적 관점에서 이것은 Hask-functor가 FHaskell 유형 의 맵임을 의미합니다 .

data F a = ...

fmapHaskell 함수 맵과 함께 :

instance Functor F where
    fmap f = ...

ML은 거의 동일하지만 fmap내가 알고있는 정식 추상화 는 없으므로 정의 해 봅시다.

signature FUNCTOR = sig
  type 'a f
  val fmap: 'a -> 'b -> 'a f -> 'b f
end

f지도 ML-types 및 fmap매핑 ML때문에, -functions을

functor StructB (StructA : SigA) :> FUNCTOR =
struct
  fmap g = ...
  ...
end

functor F: StructA -> StructB입니다.


5

"Functor는 범주의 구성과 정체성을 유지하는 객체와 형태의 매핑입니다."

카테고리가 무엇인지 정의 할 수 있습니까?

그것은 많은 물건입니다!

원 안에 몇 개의 점 (현재 2 개의 점, 하나는 'a', 다른 하나는 'b')을 그리고 그 이름을 A (Category)로 그립니다.

카테고리는 무엇을 보유하고 있습니까?

모든 사물에 대한 사물의 구성과 아이덴티티 기능.

따라서 Functor를 적용한 후 오브젝트를 매핑하고 컴포지션을 보존해야합니다.

'A'가 객체 [ 'a', 'b']를 가지고 있고 형태소 a-> b가있는 우리의 범주라고 상상해 봅시다.

이제 이러한 객체와 형태를 다른 범주 'B'에 매핑 할 수있는 펑터를 정의해야합니다.

functor는 'Maybe'라고합니다

data Maybe a = Nothing | Just a

따라서 카테고리 'B'는 다음과 같습니다.

이번에는 'a'와 'b'대신 'Maybe a'와 'Maybe b'로 다른 원을 그립니다.

모든 것이 좋아 보이고 모든 객체가 매핑됩니다

'a'는 'Maybe a'가되었고 'b'는 'Maybe b'가되었습니다.

그러나 문제는 형태를 'a'에서 'b'로 매핑해야한다는 것입니다.

그것은 'A'에서 형태소 a-> b가 형태소 'Maybe a'-> 'Maybe b'에 매핑되어야 함을 의미합니다.

a-> b의 형태를 f라고하고 'Maybe a'-> 'Maybe b'의 형태를 'fmap f'라고합니다

이제 'A'에서 'f'의 기능을 확인하고 'B'에서 복제 할 수 있는지 확인하십시오.

'A'에서 'f'의 함수 정의 :

f :: a -> b

f는 a를 취하고 b를 반환

'B'에서 'f'의 함수 정의 :

f :: Maybe a -> Maybe b

f는 아마도 a를 취하고 아마 b를 반환

fmap을 사용하여 함수 'f'를 'A'에서 'B'의 함수 'fmap f'로 매핑하는 방법을 볼 수 있습니다.

fmap의 정의

fmap :: (a -> b) -> (Maybe a -> Maybe b)
fmap f Nothing = Nothing
fmap f (Just x) = Just(f x)

우리 여기서 뭐하는거야?

'a'유형의 'x'에 'f'기능을 적용하고 있습니다. 'Nothing'의 특수 패턴 일치는의 정의에서옵니다 Functor Maybe.

그래서 우리는 객체 [a, b]와 형태 [f]를 카테고리 'A'에서 카테고리 'B'로 매핑했습니다.

저것은 Functor!

여기에 이미지 설명을 입력하십시오


흥미로운 답변. 모나드 로 보완하고 싶은 것은 부리 토스 ( 추상화, 직관 및“모 노드 튜토리얼 오류”에 대한 재미있는 답변) 와 같고 그의 문장은“펑터 F는 각 유형 T를 취하여 새로운 유형 FT에 맵핑합니다. . 함수형 프로그래밍 및 범주 이론-범주 및 펑터 도 유용했습니다.
Ludovic Kuty

3

대략적인 개요

함수형 프로그래밍에서 펑 터는 기본적으로 일반 단항 을 리프팅하는 구조입니다. 함수 (즉, 하나의 인수가있는 함수)를 새로운 유형의 변수 사이의 함수 . 일반 객체 사이에 간단한 함수를 작성하고 유지 관리하고 펑터를 사용하여 들어 올리고 복잡한 컨테이너 객체 사이에 함수를 수동으로 작성하는 것이 훨씬 쉽습니다. 또 다른 장점은 일반 기능을 한 번만 작성한 다음 다른 기능을 통해 재사용하는 것입니다.

펑터의 예로는 배열, "아마도"및 "둘 중 하나"펑터, 선물 (예 : https://github.com/Avaq/Fluture 참조 ) 및 기타 여러 가지가 있습니다.

삽화

이름에서 성 전체 이름을 구성하는 함수를 고려하십시오. 우리는 이것을 fullName(firstName, lastName)두 개의 인수의 함수 처럼 정의 할 수 있지만, 하나의 인수의 함수만을 다루는 함수에는 적합하지 않습니다. 이를 해결하기 위해 단일 인수로 모든 인수를 수집하여 name이제 함수의 단일 인수가됩니다.

// In JavaScript notation
fullName = name => name.firstName + ' ' + name.lastName

이제 배열에 많은 사람이 있다면 어떨까요? 수동으로 목록을 살펴 보는 대신 짧은 한 줄의 코드로 배열에 제공된 방법을 fullName통해 단순히 함수 를 재사용 할 수 있습니다 map.

fullNameList = nameList => nameList.map(fullName)

그리고 그것을 사용하십시오

nameList = [
    {firstName: 'Steve', lastName: 'Jobs'},
    {firstName: 'Bill', lastName: 'Gates'}
]

fullNames = fullNameList(nameList) 
// => ['Steve Jobs', 'Bill Gates']

우리의 모든 항목이 속성 과 속성을 nameList모두 제공하는 객체 일 때마다 작동 합니다. 그러나 일부 물체가 그렇지 않은 경우 (또는 전혀 물체가 아닌 경우) 어떻게해야합니까? 오류를 피하고 코드를 더 안전하게 만들기 위해 객체를 유형 으로 래핑 할 수 있습니다 (예 : https://sanctuary.js.org/#maybe-type ).firstNamelastNameMaybe

// function to test name for validity
isValidName = name => 
    (typeof name === 'object') 
    && (typeof name.firstName === 'string')
    && (typeof name.lastName === 'string')

// wrap into the Maybe type
maybeName = name => 
    isValidName(name) ? Just(name) : Nothing()

여기서 Just(name)유효한 이름 만 가진 컨테이너이며 Nothing()다른 모든 것에 사용되는 특별한 값입니다. 이제 인수의 유효성을 검사하기 위해 방해하거나 잊어 버리는 대신이 방법을 fullName다시 기반으로 다른 단일 코드 행으로 원래 함수를 재사용 (리프팅) 할 수 있습니다. map이번에는 Maybe 유형에 제공되었습니다.

// Maybe Object -> Maybe String
maybeFullName = maybeName => maybeName.map(fullName)

그리고 그것을 사용하십시오

justSteve = maybeName(
    {firstName: 'Steve', lastName: 'Jobs'}
) // => Just({firstName: 'Steve', lastName: 'Jobs'})

notSteve = maybeName(
    {lastName: 'SomeJobs'}
) // => Nothing()

steveFN = maybeFullName(justSteve)
// => Just('Steve Jobs')

notSteveFN = maybeFullName(notSteve)
// => Nothing()

카테고리 이론

범주 이론Functor 는 형태 의 구성을 고려한 두 범주 사이의 맵입니다. 안에 컴퓨터 언어 , 관심의 주요 카테고리는 누구 하나 인 객체 입니다 유형 그 (값의 특정 세트), 및 morphisms 있는 기능을 f:a->b하나 개의 유형에서 a다른 유형으로는 b.

예를 들어, 가지고 aString유형, b숫자 유형 및 f길이에 캐릭터를 매핑하는 기능입니다 :

// f :: String -> Number
f = str => str.length

여기 a = String 에는 모든 문자열 b = Number세트와 모든 숫자 세트가 표시됩니다. 그런 의미에서, 두 ab의 오브젝트 표현 집합 카테고리 (가깝게 차이가 중요하지 않은 여기 인 상태 유형의 카테고리에 관한 것이다). 세트 카테고리에서 두 세트 사이의 형태 는 정확히 첫 번째 세트에서 두 번째 세트까지의 모든 기능입니다. f여기서 길이 함수 는 문자열 집합에서 숫자 집합으로의 형태입니다.

우리는 집합 범주 만 고려하기 때문에 관련 함수 는 그 자체에서 객체를 객체로, 형태를 특정 대 수법 을 만족시키는 형태로 보내는 맵입니다.

예: Array

Array많은 것을 의미 할 수 있지만 단 하나의 유형은 Functor입니다. 유형 구조 a는 유형 [a]을 모든 유형 의 배열 유형 에 매핑 합니다.a . 예를 들어, Arrayfunctor String 는 유형 [String]( 유형 길이의 모든 문자열 배열 집합)에 유형 을 매핑하고 유형 을 Number해당 유형 [Number](모든 숫자 배열 집합)에 설정합니다.

Functor 맵을 혼동하지 않는 것이 중요합니다

Array :: a => [a]

형태로 a -> [a]. functor는 단순히 유형을 매핑 (연관)합니다a 을 유형 [a]에 다른 것으로 . 각 유형이 실제로 요소 집합이라는 점은 여기서 관련이 없습니다. 대조적으로, 형태는 그 세트들 사이의 실제 기능입니다. 예를 들어, 자연적인 형태 (기능)가 있습니다

pure :: a -> [a]
pure = x => [x]

단일 값으로 해당 값을 갖는 1 요소 배열에 값을 보냅니다. 그 기능은Array Functor 의 일부 아닙니다 ! 이 functor의 관점에서 볼 때 pure다른 기능과 마찬가지로 특별한 기능은 없습니다.

반면에 ArrayFunctor는 두 번째 부분 인 형태 부분을 가지고 있습니다. 어떤 형태 f :: a -> b를 형태 로 매핑 하는가[f] :: [a] -> [b] ?

// a -> [a]
Array.map(f) = arr => arr.map(f)

다음 arr타입의 값으로 임의의 길이의 임의의 어레이이며 a, 그리고 arr.map(f)타입의 값과 동일한 길이의 배열 b엔트리 적용한 결과이다 f의 엔트리들 arr. 그것을 functor로 만들려면, 정체성을 정체성에, 작곡을 작곡에 매핑하는 수학적 법칙이 있어야하며,이 Array예제 에서 쉽게 확인할 수 있습니다.


2

이전의 이론적 또는 수학적 대답과 모순되지는 않지만 Functor는 하나의 방법 만 가지고 있으며 함수로 효과적으로 사용되는 Object (Object-Oriented Programming Language)입니다.

예를 들어, Java의 Runnable 인터페이스는 하나의 메소드 인 run입니다.

일급 함수가있는 Javascript에서 먼저이 예제를 고려하십시오.

[1, 2, 5, 10].map(function(x) { return x*x; });

출력 : [1, 4, 25, 100]

map 메소드는 함수를 가져 와서 해당 함수를 적용한 결과 인 각 요소를 원래 배열의 동일한 위치에있는 값으로 새 배열을 리턴합니다.

Functor를 사용하여 Java와 동일한 작업을 수행하려면 먼저 인터페이스를 정의해야합니다.

public interface IntMapFunction {
  public int f(int x);
}

그런 다음 맵 함수가있는 콜렉션 클래스를 추가하면 다음을 수행 할 수 있습니다.

myCollection.map(new IntMapFunction() { public int f(int x) { return x * x; } });

이것은 IntMapFunction의 인라인 서브 클래스를 사용하여 Functor를 작성합니다. Functor는 이전 JavaScript 예제의 함수와 동등한 OO입니다.

Functors를 사용하면 기능 기술을 OO 언어로 적용 할 수 있습니다. 물론 일부 OO 언어도 기능을 직접 지원하므로 필요하지 않습니다.

참조 : http://en.wikipedia.org/wiki/Function_object


실제로 "함수 객체"는 펑터에 대한 올바른 설명이 아닙니다. 예 Array를 들어 functor이지만 Array(value)1 요소 배열 만 제공합니다.
Dmitri Zaitsev

0

키스 : 펑 터는 맵 메소드를 가진 객체입니다.

JavaScript의 배열은 맵을 구현하므로 functors입니다. 약속, 개울 및 나무는 종종 기능적 언어로지도를 구현하며, 그렇게 할 때 펑터로 간주됩니다. functor의 map 메소드는 자체 컨텐츠를 가져와 map에 전달 된 변환 콜백을 사용하여 각 컨텐츠를 변환하고 구조를 첫 번째 functor로 포함하지만 변환 된 값을 갖는 새로운 functor를 리턴합니다.

src : https://www.youtube.com/watch?v=DisD9ftUyCk&feature=youtu.be&t=76


1
부수적으로 '객체'는 매우 광범위하게 취해야하며 '무언가'를 의미합니다. 예를 들어 OOP 언어의 경우 objectclass로 대체하십시오 . 'functor는 Functor 인터페이스를 구현하는 클래스입니다'라고 말할 수 있습니다. (물론이 인터페이스는 물리적으로 존재하지 않을 수 있지만 'map'로직을 해당 인터페이스로 들어 올려서 매핑 가능한 모든 클래스가 공유하도록 할 수 있습니다. -타입 시스템이 일반적인 것을 타이핑 할 수있는 한, 즉).
Qqwy

1
나는 클래스가 정직한 것을 혼란스럽게 생각합니다. 한면에는 구체적인 무언가에 대한 청사진 일뿐입니다. 그러나 메소드 (정적 항목)가있을 수 있으며 객체처럼 작동 할 수 있습니다. 클래스가 생성 한 인터페이스 또는 인스턴스를 구현합니까?
soundyogi 2016 년

1
예, 혼란 스러울 수 있습니다. 그러나 클래스 인터페이스를 구현 합니다 (인터페이스 메소드에 제공된 공백을 '채우고 있습니다'. 즉, 인터페이스의 추상 지침을 구체적인 지침으로 설정하여 즉각적으로 (펑크를 용서할 수 있음) 인스턴스화 할 수 있습니다. '클래스가 객체처럼 동작합니다': 루비와 같은 OOP 언어에서 클래스는 '클래스'클래스의 인스턴스입니다. 거북은 끝이야
Qqwy

Arraytype 구문은 단일 functor를 정의합니다. 인스턴스는 "배열"이라고도하지만 펑 터는 아닙니다. 여기에 설명이 더 정확해야합니다.
Dmitri Zaitsev

@DmitriZaitsev 좀 더 자세히 설명해 주시겠습니까? 당신이 말하는 것은 인스턴스가 펑터가 아니라는 것입니다. 나는 당신이 하나 이상의 매핑하여 새로운 functor를 얻었으므로 그 의미를 보지 못합니다.
soundyogi

-4

실제로 functor는 C ++에서 호출 연산자를 구현하는 객체를 의미합니다. ocaml에서 functor는 모듈을 입력으로 사용하고 다른 모듈을 출력하는 것을 말합니다.


-6

간단히 말해서, functor 또는 함수 객체는 함수처럼 호출 할 수있는 클래스 객체입니다.

C ++에서 :

이것이 함수를 작성하는 방법입니다

void foo()
{
    cout << "Hello, world! I'm a function!";
}

이것은 당신이 functor를 쓰는 방법입니다

class FunctorClass
{
    public:
    void operator ()
    {
        cout << "Hello, world! I'm a functor!";
    }
};

이제 당신은 이것을 할 수 있습니다 :

foo(); //result: Hello, World! I'm a function!

FunctorClass bar;
bar(); //result: Hello, World! I'm a functor!

이것들을 아주 좋게 만드는 것은 클래스에서 상태를 유지할 수 있다는 것입니다-함수가 호출 된 횟수를 함수에 물어보고 싶다면 상상하십시오. 깔끔하고 캡슐화 된 방식으로이 작업을 수행 할 방법이 없습니다. 함수 객체를 사용하면 다른 클래스와 같습니다. 증가하는 인스턴스 변수 operator ()와 해당 변수를 검사하는 메소드가 있으며 원하는대로 모든 것이 깔끔합니다.


12
아니요, 이러한 기능은 FP 언어에서 사용되는 유형 이론 개념이 아닙니다.
Tobu

1
나는 FunctorClass첫 번째 Functor 법 을 충족시키는 방법을 어떻게 증명할 수 있는지 알 수 있지만 두 번째 법칙에 대한 증거를 제시 할 수 있습니까? 나는 그것을 잘 보지 못한다.
Jörg W Mittag

3
바, 너희들이 맞아. 나는 "웹이 너무 많은 기술적 인 설명을 제공했다"는 문제를 극복하고 지나친 것을 피하려고 노력했다. "ML ML 언어에서 펑 터는 하나 이상의 다른 모듈을 매개 변수로 취하는 모듈이다." 그러나이 대답은 나쁘다. 과도하게 단순화되고 과소 평가되었습니다. 나는 그것을 ragedelete하고 싶은 유혹이있다, 그러나 나는 다음 세대에 그들의 머리를 흔들게하기 위해 그것을 떠날 것이다 :)
Matt

문제의 틀을 잡는 데 도움이되기 때문에 답변과 의견을 남겼습니다. 감사합니다! 나는 대부분의 답변이 Haskell 또는 OCaml로 작성되었다는 점에서 어려움을 겪고 있으며 악어에 대해 악어를 설명하는 것과 조금 비슷합니다.
Rob

-10

Functor는 기능 프로그래밍과 특별히 관련이 없습니다. 함수 나 객체에 대한 "포인터"일 뿐이며 함수처럼 호출 될 수 있습니다.


8
펑터 (functor)의 특정 FP 개념 (범주 이론으로부터)이 있지만, 같은 단어가 FP 이외의 언어로 다른 것들에도 사용되는 것이 맞습니다.
Craig Stuntz

함수 포인터가 Functors인지 확인 하시겠습니까? 함수 포인터가 두 가지 Functor Law, 특히 두 번째 Functor Law (형태 구성 보존)를 어떻게 충족시키는 지 알 수 없습니다. 이에 대한 증거가 있습니까? (거친 스케치)
Jörg W Mittag
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.