[haskell] 하스켈에서 “리프팅”이란 무엇입니까?

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



답변

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

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

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에 리프트 기능을 사용하는 대신 데이지 체인을 사용합니다.


답변

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

들어 올리는 함수는 임의의 수의 인수를 가질 수 있으며 동일한 유형일 필요는 없다고 덧붙이고 싶습니다. 예를 들어 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실용적 (뿐만 아니라 다른 종류의 클래스를, 스크롤 해당 문서의 오른쪽 장에 이르기까지).

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


답변

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

> 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. 하나의 모나드의 모나드 동작을 변환 된 모나드의 동작으로 변환합니다.

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

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


답변

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

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


답변

이 반짝이는 튜토리얼 에 따르면 , 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>입니다.


답변