하스켈에서 "리프팅"이란 무엇입니까?


138

나는 "리프팅"이 무엇인지 이해하지 못한다. "리프트"가 무엇인지 이해하기 전에 모나드를 먼저 이해해야합니까? (모나드에 대해서도 완전히 무지합니다.) 아니면 누군가가 간단한 단어로 나에게 설명 할 수 있습니까?


9
아마 유용하지 않을 수도 있습니다 : haskell.org/haskellwiki/Lifting
kennytm

답변:


179

리프팅은 수학적 개념보다 디자인 패턴에 가깝습니다. (여기서는 주변 사람들이 리프트가 카테고리 또는 어떤 방식인지 보여줌으로써 나를 반박 할 것으로 예상하지만).

일반적으로 매개 변수가있는 일부 데이터 유형이 있습니다. 같은 것

data Foo a = Foo { ...stuff here ...}

Foo숫자 유형 ( Int, Double등)을 많이 사용 하고 이러한 숫자를 풀고, 더하거나 곱한 다음 다시 랩핑하는 코드를 계속 작성해야 한다고 가정하십시오 . 랩핑 해제 랩 코드를 한 번 작성하여이를 단락시킬 수 있습니다. 이 기능은 전통적으로 "리프트"라고합니다.

liftFoo2 :: (a -> b -> c) -> Foo a -> Foo b -> Foo c

즉, (+)연산자 와 같은 2 인수 함수 를 사용하여 Foos에 해당하는 함수로 바꾸는 함수가 있습니다.

이제 쓸 수 있습니다

addFoo = liftFoo2 (+)

편집 : 추가 정보

당신은 물론 수 liftFoo3, liftFoo4등등. 그러나 이것은 종종 필요하지 않습니다.

관찰로 시작

liftFoo1 :: (a -> b) -> Foo a -> Foo b

그러나 그것은 정확히 동일합니다 fmap. 그래서 liftFoo1당신이 쓰는 것보다

instance Functor Foo where
   fmap f foo = ...

완전한 규칙 성을 원한다면 말할 수 있습니다.

liftFoo1 = fmap

Foofunctor로 만들 수 있다면 아마도 functor로 만들 수 있습니다. 실제로 작성할 수 있으면 liftFoo2적용 인스턴스는 다음과 같습니다.

import Control.Applicative

instance Applicative Foo where
   pure x = Foo $ ...   -- Wrap 'x' inside a Foo.
   (<*>) = liftFoo2 ($)

(<*>)Foo 의 연산자는 다음과 같은 유형입니다.

(<*>) :: Foo (a -> b) -> Foo a -> Foo b

랩핑 된 기능을 랩핑 된 값에 적용합니다. 따라서 구현할 수 있다면 liftFoo2이것을 관점에서 작성할 수 있습니다. 또는 모듈에 포함되어 liftFoo2있기 때문에 직접 구현할 수 있습니다.Control.Applicative

liftA2 :: Applicative f => (a -> b -> c) -> f a -> f b -> f c

마찬가지로있다 liftAliftA3. 그러나 다른 연산자가 있기 때문에 실제로 자주 사용하지는 않습니다.

(<$>) = fmap

이것은 당신이 쓸 수 있습니다 :

result = myFunction <$> arg1 <*> arg2 <*> arg3 <*> arg4

이 용어 myFunction <$> arg1는 Foo로 래핑 된 새 함수를 반환합니다. 이것은 차례로 다음을 사용하여 다음 인수에 적용될 수 있습니다 (<*>). 이제 모든 arity에 리프트 기능을 사용하는 대신 데이지 체인을 사용합니다.


26
이 리프트는 표준 법률 존중해야한다는 아마도 가치가 연상의 lift id == idlift (f . g) == (lift f) . (lift g).
Carlos Scheidegger

13
리프트는 실제로 "범주 또는 무언가"입니다. 카를로스는 단지 펑터 법을 나열 곳에있다 id.신원 화살표를 각각 일부 카테고리의 구성을 화살표입니다. 하스켈의 말할 때 일반적으로, 문제의 범주는 그 화살표입니다 하스켈 기능 (즉, "Hask"입니다 id.하스켈 기능을 참조하십시오 당신이 알고 사랑).
Dan Burton

3
이 읽어야 instance Functor Foo하지, instance Foo Functor오른쪽? 나는 나 자신을 편집했지만 100 % 확실하지 않습니다.
amalloy

2
Applicative없이 들어 올리는 것은 = Functor입니다. Functor 또는 Applicative Functor 두 가지 중에서 선택할 수 있습니다. 첫 번째는 단일 매개 변수 기능을, 두 번째 다중 매개 변수 기능을 해제합니다. 그게 다야. 권리? 그것은 로켓 과학이 아닙니다 :) 그냥 소리처럼 들립니다. 큰 답변 btw 주셔서 감사합니다!
jhegedus

2
@atc : 이것은 부분적인 적용입니다. 참조 wiki.haskell.org/Partial_application
폴 존슨

41

바울과 야 이르 쿠는 모두 좋은 설명입니다.

들어 올리는 함수는 임의의 수의 인수를 가질 수 있으며 동일한 유형일 필요는 없다고 덧붙이고 싶습니다. 예를 들어 liftFoo1을 정의 할 수도 있습니다.

liftFoo1 :: (a -> b) -> Foo a -> Foo b

일반적으로 1 개의 인수를 취하는 함수의 리프팅은 type 클래스에서 캡처되며 Functor리프팅 작업은 fmap다음과 같습니다.

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

liftFoo1의 유형 과의 유사성을 주목하십시오 . 실제로, 가지고 있다면 다음과 같은 인스턴스를 liftFoo1만들 수 있습니다 .FooFunctor

instance Functor Foo where
  fmap = liftFoo1

또한 임의의 수의 인수로 승화하는 일반화를 적용 스타일 이라고 합니다 . 고정 된 수의 인수로 함수의 리프팅을 파악할 때까지이 작업에 신경 쓰지 마십시오. 그러나 당신이 할 때 , Haskell 이 이것에 대해 좋은 장을 가지고 있음을 배우십시오 . Typeclassopedia는 설명 또 다른 좋은 문서입니다 은 Functor실용적 (뿐만 아니라 다른 종류의 클래스를, 스크롤 해당 문서의 오른쪽 장에 이르기까지).

도움이 되었기를 바랍니다!


25

예제로 시작해 보겠습니다 (더 명확한 표현을 위해 공백이 추가됨).

> import Control.Applicative
> replicate 3 'a'
"aaa"
> :t replicate
replicate        ::         Int -> b -> [b]
> :t liftA2
liftA2 :: (Applicative f) => (a -> b -> c) -> (f a -> f b -> f c)
> :t liftA2 replicate
liftA2 replicate :: (Applicative f) =>       f Int -> f b -> f [b]
> (liftA2 replicate) [1,2,3] ['a','b','c']
["a","b","c","aa","bb","cc","aaa","bbb","ccc"]
> ['a','b','c']
"abc"

liftA2일반 유형의 함수 를 목록 등과 같은에 래핑 된 동일한 유형Applicative 의 함수로 변환합니다 IO.

또 다른 일반적인 리프트는 lift입니다 Control.Monad.Trans. 하나의 모나드의 모나드 동작을 변환 된 모나드의 동작으로 변환합니다.

일반적으로, "리프트" 리프트 (원래의 함수 "는 랩에서"작업에 도달 있도록)는 "포장"유형으로 기능 / 동작을.

이것을 이해하고 모나드 등을 이해하고 유용한 이유를 이해하는 가장 좋은 방법은 아마도 그것을 코딩하고 사용하는 것입니다. 이전에 코딩 한 것이 이로 인해 혜택을받을 수 있다고 생각되는 경우 (즉, 코드를 더 짧게 만드는 등) 시도해 보면 개념을 쉽게 파악할 수 있습니다.


13

리프팅은 함수를 다른 (일반적으로 더 일반적인) 설정 내에서 해당 함수로 변환 할 수있는 개념입니다.

http://haskell.org/haskellwiki/Lifting보십시오


40
네,하지만 그 페이지는 "우리는 보통 (공변량) 펑터로 시작합니다 ..."로 시작합니다. 초보자에게는 친절하지 않습니다.
Paul Johnson

3
그러나 "functor"는 연결되어 있으므로 초보자는이를 클릭하여 Functor가 무엇인지 확인할 수 있습니다. 분명히, 링크 된 페이지는 좋지 않습니다. 계정을 얻어서 수정해야합니다.
jrockway

10
다른 함수형 프로그래밍 사이트에서 본 문제입니다. 각 개념은 초보자가 완전히 원을 그리며 구부릴 때까지 다른 개념 (익숙하지 않은)으로 설명됩니다. 재귀를 좋아하는 것과 관련이 있어야합니다.
DNA

2
이 링크에 투표하십시오. 리프트는 한 세계와 다른 세계를 연결합니다.
eccstartup

3
이 답변은 이미 주제를 이해 한 경우에만 유용합니다.
doubleOrt

-2

이 반짝이는 튜토리얼 에 따르면 , functor는 (예를 들어 Maybe<a>, List<a>또는 Tree<a>다른 유형의 요소를 저장할 수 있는) 컨테이너 a입니다. 나는 <a>엘리먼트 타입에 자바 제네릭 표기법을 사용 a했고 엘리먼트를 트리의 베리로 생각했다 Tree<a>. 함수가 fmap소자 변환 기능, 소요 a->b및 용기 functor<a>. 그것은 적용 a->b효율적으로 변환 컨테이너의 모든 요소 functor<b>. 첫 번째 인수 만 제공되면 a->bfmap기다립니다 functor<a>. 즉, 공급 a->b만하면이 요소 레벨 기능 functor<a> -> functor<b>이 컨테이너 에서 작동 하는 기능으로 바뀝니다 . 이것을 리프팅 이라고합니다기능의. 컨테이너는 functor 라고도 하므로 Monads 대신 Functors가 리프팅의 전제 조건입니다. 모나드는 리프팅에 대한 "병렬"의 일종입니다. 둘 다 Functor 개념에 의존하고 있습니다 f<a> -> f<b>. 차이점은 a->b전환에 리프팅 사용 을 사용 하는 반면 Monad는 사용자가 정의해야한다는 것 a -> f<b>입니다.


5
"functor is some container"는 트롤 맛의 화염 미끼이기 때문에 나는 당신에게 표를 주었다. 예 : 일부 r에서 유형으로 ( c다양한 용도로 사용 ) 함수 는 Functors입니다. 그들은 어떤 것도 포함하지 않습니다 c. 이 경우, fmap은 함수 a -> br -> a하나를 취하여 새로운 r -> b함수 를 제공하는 함수 구성입니다. 여전히 컨테이너가 없으며 가능한 경우 최종 문장으로 다시 표시합니다.
BMeph

1
또한 fmap함수이며 어떤 것도 "기다리지"않습니다. Functor가되는 "컨테이너" 는 리프팅의 핵심 입니다. 또한, 모나드는, 만약 아무것도, 리프팅에 이중 아이디어 같습니다 모나드 당신은 단지 해제 된 것처럼 한 번, 시간의 일부 양수 해제 된 것을 사용할 수 있습니다 -이 더 잘 알려져 있습니다 병합을 .
BMeph

1
@BMeph To wait, to expect, to anticipate동의어입니다. "기능 대기"라고 말함으로써 "기능 기대"를 의미했습니다.
Val

@ BMeph 나는 함수가 컨테이너라는 아이디어에 대한 반례로 함수를 생각하는 대신 함수의 제정 한 functor 인스턴스를 함수가 컨테이너가 아니라는 아이디어의 반례로 생각해야한다고 말하고 싶습니다. 함수는 도메인에서 코 도메인으로의 매핑이며 도메인은 모든 매개 변수의 교차 곱이며 코 도메인은 함수의 출력 유형입니다. 같은 방법으로 목록은 Naturals에서 목록의 내부 유형 (도메인-> 공동 도메인)으로의 맵핑입니다. 함수를 기억하거나 목록을 유지하지 않으면 더 비슷해집니다.
세미콜론

@BMeph 컨테이너와 같은 것으로 생각되는 유일한 이유 중 하나는 많은 언어에서 변경 될 수 있지만 전통적으로 함수는 불가능하다는 것입니다. 그러나 Haskell 에서는 둘 다 변이 될 수 없으며 , 둘 다 복사 변이 될 수 있으므로 공정한 진술이 아닙니다. b = 5 : a그리고 f 0 = 55 f n = g n둘 다 "컨테이너"를 의사-돌연변이시킵니다. 또한 목록은 일반적으로 메모리에 완전히 저장되는 반면 함수는 일반적으로 계산으로 저장됩니다. 그러나 호출 사이에 저장되지 않은 메모 / 단일 목록은 둘 다 그 아이디어를 허물어 버립니다.
세미콜론
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.