2017-09-06 1 views
3

GHC의 ScopedTypeVariables은 기능 패턴에서 유형 변수를 바인딩 할 수 있지만 패턴은 사용할 수 없음을 알아 챘습니다.하스켈의 범위 변수가 패턴 바인딩에서 변수의 바인딩을 허용하지 않는 이유는 무엇입니까?

fooType :: Foo -> TypeRep 
fooType (Foo x) = 
    let (_ :: a) = x 
    in typeRep (Proxy::Proxy a) 

을하지만,이 트릭을 사용 : 나는 푸 내부 유형에 액세스하려면 최소한의 예를 들어

이 유형

data Foo where Foo :: Typeable a => a -> Foo 

을 고려, 다음 함수는 컴파일되지 않습니다 형식 변수 바인딩을 함수 호출로 이동하려면 문제없이 작동합니다.

let 바인딩은 실제로 위장의 함수 바인딩이기 때문에 위의 두 코드 스 니펫은 왜 동일하지 않습니까?

(이 예에서, 다른 솔루션은 최상위 함수에서 x :: a으로 직접 변수를 typeOf xTypeRep을 만들거나 결합하는 것입니다. 이러한 옵션 중 어느 것도 내 진짜 코드에서 사용할 수 있으며, 그들을 '아무튼 사용 질문에 대답 해주세요.)

+0

: 코드에 관해서는

ScopedTypeVariables 실제로 당신에게 훨씬 더 간결 옵션을 제공합니다'fooType (푸 X)를 = typeRep [X] '는'typeRep'에 대한'proxy'가 임의의 펑터가 될 수 있다는 사실을 이용하여 작동합니다 : 반드시 사소한'Proxy'가 아니라 실제로'a' 값을 포함 할 수도 있습니다! – leftaroundabout

+1

@leftaround 우리가 타입 변수를 없애고 있다면 더 멀리 가서'fooType (Foo x) = typeOf x'라고 말할 수 있습니다. 나는 앞서 가서 실제 사용 케이스가 타입 변수에 대한 액세스를 갖는 것이 중요한 부분이라고 생각했습니다. – Carl

+0

@Carl yeah하지만 실제로'x' 값을 포함하는 구체적인 컨테이너로'proxy x' 인수를 가진 _any_ 함수를 호출 할 수 있다는 것은 일반적으로 알려져 있지 않습니다. – leftaroundabout

답변

7

큰 점은, 기능이 case 위장한 표현이 아니고 let 표현입니다. case 일치 및 let 일치가 다른 의미를가집니다. 또한 let 표현식에서 유형을 구체화하는 GADT 생성자와 일치시킬 수없는 이유이기도합니다.

차이점은 case이 일치하기 전에 계속 진행하기 전에 조사를 평가하는 반면 let은 "결과가 요구 될 때 평가 수행"이라는 힙에 썽크를 던집니다. GHC는 게으름이 그들과 상호 작용할 수있는 모든 잠재적 인 방법에 걸쳐 지역 범위 유형 (예 : a)을 유지하는 방법을 알지 못하므로 시도하지 않습니다. 지역 범위 유형이 관련된 경우 게으름이 문제가 될 수 없도록 case 표현식을 사용하십시오. 당신은 명시 적으로 전혀 타입의 변수를 도입 할 필요가 없습니다

{-# Language ScopedTypeVariables, GADTs #-} 

import Data.Typeable 
import Data.Proxy 

data Foo where 
    Foo :: Typeable a => a -> Foo 

fooType :: Foo -> TypeRep 
fooType (Foo (x :: a)) = typeRep (Proxy :: Proxy a) 
+0

내 코드에서 제공된 솔루션을 사용할 수는 없지만 대소 문자에 대한 설명과 let 표현식이 질문에 대답합니다. 그것은 도우미 기능을 사용하는 것보다 더 우아한 해결책입니다. 감사! – Theelepel

+0

STV가 필요합니까? 만약 어떤 이유로'typeRep'을 사용하고 싶다면'fooType (Foo x) = typeOf x' 또는'fooType (Foo x) = typeRep [x]' –

관련 문제