저는 하스켈을 처음 접했고, 저는 펑터와 응용 펑터에 대해 읽었습니다. 좋아, 나는 펑터를 어떻게 사용할 수 있는지 이해하지만, 왜 신청자 펑터가 유용하고 어떻게 내가 하스켈에서 사용할 수 있는지 이해할 수 없다. 왜 내가 펑 터터를 필요로하는지 간단한 예를 들어 설명해 주시겠습니까?Functional Programming에서 응용 펑터를 사용해야하는 이유는 무엇입니까?
답변
Applicative functors은 펑터와 monads 사이의 중간 점을 제공하므로 펑터보다 유용하지만 모나드보다 더 광범위합니다. 일반적으로 함수를 펑터로 매핑 할 수 있습니다. 응용 펑터를 사용하면 펑터 컨텍스트에있는 여러 값에서 작동하는 "일반"함수 (비 펑션 인수를 사용)를 사용할 수 있습니다. 결과로서 모나드없이 효과적인 프로그래밍이 가능합니다.
예제가 포함 된 멋진 자체 설명은 here입니다. 또한 사전 지식이 필요하지 않은 Bryan O'Sullivan이 개발 한 a practical parsing example을 읽을 수 있습니다.
도움이되는 링크가 있지만 질문에 대답하기 위해 초점을 맞춘 간단한 간단한 예를 대체 할 수 있다고 생각하지 않습니다. 중요하지 않은 세부 정보는 가능한 한 많이 제거했습니다. –
작풍에 Conor McBride와 로스 Paterson의 Functional Pearl에는 몇몇 좋은 본보기가있다. 그것은 또한 처음부터 스타일을 대중화하는 책임이 있습니다. 그들은 "적용 할 수있는 functor"에 "관용구"라는 용어를 사용하지만, 그 이외에는 꽤 이해할 수 있습니다.
하나의 좋은 예 : 적용 가능한 구문 분석. 이것은 DO-표기법 파서 코드 http://book.realworldhaskell.org/read/using-parsec.html#id652517
참조 [실제 하스켈] CH16 :
-- file: ch16/FormApp.hs
p_hex :: CharParser() Char
p_hex = do
char '%'
a <- hexDigit
b <- hexDigit
let ((d, _):_) = readHex [a,b]
return . toEnum $ d
사용 펑 만들 그것을훨씬 짧은 :
-- file: ch16/FormApp.hs
a_hex = hexify <$> (char '%' *> hexDigit) <*> hexDigit
where hexify a b = toEnum . fst . head . readHex $ [a,b]
'들어 올리기'는 반복 코드의 기본 세부 사항을 숨길 수 있습니다. 정확한 단어를 정확하게 말하기 위해 더 적은 단어를 사용할 수 있습니다.
"훨씬 더 짧다"는 이상한 아이디어가 있습니다 - 적용 버전은 7 자 이상입니다! –
@Daniel Wagner : -_- || 오, 내 .. 너는 코드에 대한 좋은 통찰력을 가지고있다. 나는 고백해야한다. 나는 실제로 '수직으로 더 짧다'는 것을 의미한다. :) – Nybble
글쎄, Control.Monad 라이브러리의 공통 함수를 사용하여 더 짧게 쓸 수있다 :'char '%'>> liftM (toEnum .fst. head. readHex) (replicateM 2 hexDigit)' . – HaskellElephant
적용 펑터는 작업 순서 지정이 필요할 때 유용하지만 중간 결과의 이름을 지정하지 않아도됩니다. 따라서 모나드보다 약하지만 펑터보다 강력합니다 (명시 적 바인드 연산자가 없지만 펑터 내에서 임의 함수를 실행할 수 있음).
언제 유용합니까? 일반적인 예는 파싱입니다. 여기서는 데이터 구조의 일부를 순서대로 읽는 여러 작업을 실행 한 다음 모든 결과를 함께 묶어야합니다. 이 기능 조성물의 일반적인 형태처럼 다음 펑이 결과에 적용 할 당신이 그렇게에 대한 임의의 조치를 실행하기 a
, b
생각할 수
f a b c d
및 f
한다.
f <$> a <*> b <*> c <*> d
저는 '공백'이 오버로드 된 것으로 생각합니다. 또는 정규 Haskell 함수는 신원 확인 펑터에 있습니다.
그것은 예 마련하기 어렵다 당신이 필요 실용적 펑터. 대부분의 소개 텍스트가 Applicative Functor를 편리한 인터페이스로만 사용하는 모나드에서 파생 된 인스턴스를 제시하기 때문에 중급 하스켈 프로그래머가 그 질문을 스스로에게 묻는 이유를 이해할 수 있습니다.
주요 통찰력은 주제와 관련된 대부분의 소개에서 언급했듯이 Applicative Functor는 Functor와 Monads (Functor와 Arrows 사이에서도) 사이에 있습니다. 모든 모나드는 적용 펑터이지만 모든 펑터가 적용되지는 않습니다.
필연적으로, 우리는 모나드 연결자를 사용할 수없는 것을 위해 응용 가능한 연결자를 사용할 수 있습니다. 그 중 하나가 ZipList
(this SO question for some details 참조)이며, 다른 Applicative 인스턴스을 목록의 Monad 인스턴스에서 파생 된 것보다 많게하기 위해리스트를 감싸는 래퍼입니다. here을 지적
f <$> ZipList xs1 <*> ... <*> ZipList xsn = ZipList (zipWithn f xs1 ... xsn)
, 거의 ZipList 작동 기발한 모나드 인스턴스를 만들 수 있습니다 다음과 실용적 문서에 대해 무엇 ZipList
의 직관적 인 개념을 제공하기 위해 다음 줄을 사용합니다.
모나드가 아닌 다른 응용 펑터 (this SO 질문)가 있으며 쉽게 이해할 수 있습니다. Monads에 대한 다른 인터페이스가 있으면 좋지만 모든 경우 Monad를 만드는 것은 비효율적이거나 복잡하거나 불가능할 수도 있습니다. 이 필요합니다. Applicative Functors.
면책 조항 : 의심, 실용적 펑의 올바른 사용을 위해 해당 지역의 카테고리 이론가를 참조 할 때 실용적 펑터를 만드는 것은 또한, 비효율적 복잡하고, 불가능할 수도 있습니다.
또한 예를 들어 실용적 프로그래밍 스타일의 몇 가지 기능을 보여
import Control.Applicative
hasCommentA blogComments =
BlogComment <$> lookup "title" blogComments
<*> lookup "user" blogComments
<*> lookup "comment" blogComments
에게있어 기사의 끝에서 this
살펴보고 제안했다. 데이터 구조의
어떤 종류의 조성물 강력한 유형을 인정하지만, 정말 모나드를 할 수 없습니다 : 내 경험에
는 실용적 펑은 다음과 같은 이유로 중대하다. 사실, 기능적 반응 형 프로그래밍의 추상화는 대부분이 범주에 속합니다. 우리는 기술적으로 예를 들어 Behavior
(일명 Signal
) 모나드는 일반적으로 효율적으로 수행 할 수 없습니다. 적용 펑터는 효율성을 희생시키지 않으면서도 강력한 구성을 여전히 유지할 수 있습니다 (확실히 모나드보다 응용 프로그램을 사용하는 것이 조금 까다 롭습니다. 작업 할 구조가별로 없기 때문입니다).
응용 펑터에서 데이터 의존성이 부족하여 예를 들어. 데이터를 사용할 수 없어도 생성 될 수있는 모든 효과를 찾는 작업을 탐색합니다.그래서 당신과 같이 사용되는 "웹 양식"실용적, 상상할 수 :
userData = User <$> field "Name" <*> field "Address"
을 당신이 사용되는 모든 필드를 찾아 형태를 표시 통과 할 엔진을 쓸 수, 당신은 데이터를 얻을 때 다시 그것을 실행하여 구축 된 User
을 얻으십시오. 모나드로는 표현할 수 있기 때문에,도 모나드 (이 두 가지 중 하나에 형태를 결합하기 때문에) 이것은 일반 펑 수행 할 수 없습니다 :
userData = do
name <- field "Name"
address <- field $ name ++ "'s address"
return (User name address)
렌더링 할 수없는 때문에 두 번째 필드의 이름은 할 수 없습니다 이미 첫 번째 응답을받지 않고 알 수 있습니다. 저는이 형식 아이디어를 구현하는 라이브러리가 있음을 확신합니다. 저는이 프로젝트와 그 프로젝트를 위해 몇 번 자신을 굴렸습니다.
응용 펑터에 대한 또 다른 좋은 점은 이입니다. 보다 구체적으로, 조성물은 펑 : f
및 g
는마다
newtype Compose f g x = Compose (f (g x))
실용적이다. 모나드는 모나드 변압기의 이야기 전체를 만들어내는 불쾌한 방식으로 복잡해집니다. 응용 프로그램은 이런 식으로 슈퍼 깨끗하고 작은 구성 가능한 구성 요소에 초점을 맞춤으로써 필요한 유형의 구조를 구축 할 수 있음을 의미합니다.
최근에 ApplicativeDo
확장이 GHC에 나타났습니다.표기법을 적용 할 수 있으므로 어떤 복잡한 일도하지 않는 한 표기법의 복잡성을 완화 할 수 있습니다.
가능한 중복 : [어떻게하면 더 깨끗한 하스켈을 작성하기 위해 Control.Applicative를 사용합니까?] (http://stackoverflow.com/questions/2104446/how-do-you-use-control-applicative-to-write-cleaner) -haskell) –
이 링크는 내가 줄 수있는 링크 일 뿐이지 만 [여기] (http://www.haskell.org/haskellwiki/Applicative_functor)는 Applicative Functors에 대한 훌륭한 설명으로 예제를 제공합니다. – Hartmut