2017-11-08 20 views
4

고양이/Scalaz의 기본 예제를 다루었으며 튜토리얼을 통해 느낌을 얻었으며 확실한 케이스를 쳤습니다. 에 대한 해결책이 있습니다.하위 클래스 (cats/scalaz)를 사용하여 Functor로 일반 함수 호출하기

그것은 <: F 인 컨텍스트 펑터 뷰 (F[_] : Functor)와 상황화 값 (F[A])를 얻어 일반화 된 함수를 호출 할 수 있는가? 나는 Functor가 F[_] 타입에서 불변하다고 알고 있고, 또한 Functor.widen이라는 존재를 알고 있습니다.하지만 일반적인 함수에서 사용하기 위해 내 타입을 암시 적으로 넓힐 방법이 없다는 것이 이상하게 보입니다.

고양이의 예 (Scalaz와 유사한 예뿐만 아니라 존재) : 명시 적 옵션 및 매핑에 대한은 Functor를 소환 물론

import cats.instances.all._ 
import cats.syntax.all._ 

def takesAFunctor[F[_] : cats.Functor](f: F[Int]) = f.map(_ + 1) 

takesAFunctor(Option(1)) // Works fine (of course) 
takesAFunctor(Some(1)) // No implicit for Functor[Some]. Makes sense, but can we summon one since we have a Functor[Option]? 
takesAFunctor(Some(1): Option[Int]) // Works but very verbose 

가 예상 작품 그래서

Functor[Option].map(Some(1))(_ + 1) // Some(2) 

내 질문에 is : 일반 함수의 시그니처가 서브 클래 싱 된 컨텍스트를 설명하기 위해 변경되어야하는지, 내가 모르는 일종의 "암시 적 확장"이 있는지, 아니면 스칼라의 함수 프로그래밍에 대한 불행한 결점이 stdlib?

답변

1

Dmytro의 답변에 나와있는 것처럼 일반적으로 가능하지 않습니다. cat/scalaz가 Option을 반환하는 것으로 입력 된 .some 확장 메서드를 노출하는 이유는 Some 생성자를 사용하면 Some을 반환하지만,

takesAFunctor(1.some)

는 다른 방법으로 당신은 더 일반적인 Apply 구문을 사용할 수 있습니다; takesAFunctor(1.pure[Option])

내가 모르는, 또는이는 다음 stdlib를 사용하여 스칼라에서 함수형 프로그래밍에 그냥 불행한 단점이다 "암시 적 확대"어떤 종류가 있습니까?

Option 펑터를 수동으로 불러올 때 나타나는 암시적인 확대는 공분산입니다. 이 인스턴스는 Option에 대해 항상 정의되어 있습니다. 따라서 Some을 사용할 수 없습니다. 컴파일러는 암시 적으로 찾을 수 없지만 Functor[Option].mapOption 또는 하위 유형 Option을 필요로합니다. 일부는 작동합니다. 여기에 언급

의 단점은 기본적으로 자바 틱 공변 하위 유형과 더 하스켈 틱를 가변 입력 typeclasses

+0

A-ha! 이것은 내가 찾고 있었던 바로 그 것이었다. 고맙습니다! 나는 Function Variance를 고려하기를 완전히 소홀히했다. 그것은 많은 의미를 가진다. –

1
// No implicit for Functor[Some]. 
// Makes sense, but can we summon one since we have a Functor[Option]? 

어떻게 일반적인 경우 이러한 인스턴스를 정의 할 것인가? functor.map(ga)(f)은 일반적으로 유형 F[B]과 반드시 ​​G[B] 때문에

implicit def subtypeFunctor[F[_], G[T] <: F[T]](implicit functor: Functor[F]): Functor[G] = new Functor[G] { 
    override def map[A, B](ga: G[A])(f: A => B): G[B] = functor.map(ga)(f) 
    } 

이 작동하지 않습니다.

일반적으로 아니요, 하위 유형 생성자에 대한 펑터를 유도하는 것은 불가능하며 이유는 근본입니다.

FunctorF지도 map(f): F[A] => F[B] (더하기 몇 가지 법률을) morphisms하는 객체 F[T] 및 morphisms f: A => BT 객체. FF[B]은 공변 (covariant) 위치에 있고 의 F은 역행 (contravariant) 위치에 있으므로 functor 유형 클래스의 유일한 옵션은 유형 생성자에서 불변합니다.

takesAFunctortakesAFunctor[Option](Some(1))으로 부를 수도 있습니다.

+1

이 좋은 고장입니다, 감사합니다 사이의 임피던스 부정합이다. Functor가 현재 상황에 따라 변하지 않는 이유에 대한 개념을 이해하고 있다고 생각합니다. 필자가 시도한 모든 것이 작동하지 않는 이유를 설명하는 데 도움이됩니다. –