2014-07-14 9 views
5

를 사용하면 코드입니다 :모나드 순위-2 타입 여기

{-# LANGUAGE RankNTypes, FlexibleContexts, ScopedTypeVariables #-} 

module Foo where 

import Data.Vector.Generic.Mutable as M 
import Data.Vector.Generic as V 
import Control.Monad.ST 
import Control.Monad.Primitive 
import Control.Monad 

data DimFun v s r = 
    DimFun {dim::Int, func :: v (PrimState s) r -> s()} 

runFun :: (Vector v r) => 
    (forall s . (PrimMonad s) => DimFun (Mutable v) s r) -> v r -> v r 
runFun t x = runST $ do 
    y <- thaw x 
    evalFun t y 
    unsafeFreeze y 

evalFun :: (PrimMonad s, MVector v r) => DimFun v s r -> v (PrimState s) r -> s() 
evalFun (DimFun dim f) y | dim == M.length y = f y 

fm :: (MVector v r, PrimMonad s, Num r, Monad m) => m (DimFun v s r) 
fm = error "" 

f :: forall v r m . (Vector v r, Num r, Monad m) => m (v r -> v r) 
f = liftM runFun $ (fm :: forall s . (PrimMonad s) => m (DimFun (Mutable v) s r)) 

이 오류가 발생합니다

Couldn't match type ‘DimFun (Mutable v) s0 r’ 
       with ‘forall (s :: * -> *). PrimMonad s => DimFun (Mutable v) s r’ 
Expected type: DimFun (Mutable v) s0 r -> v r -> v r 
    Actual type: (forall (s :: * -> *). 
       PrimMonad s => 
       DimFun (Mutable v) s r) 
       -> v r -> v r 
Relevant bindings include 
    f :: m (v r -> v r) (bound at Testing/Foo.hs:36:1) 
In the first argument of ‘liftM’, namely ‘runFun’ 
In the expression: liftM runFun 

는 그러나, 나는 수정하거나 문제를 진단하는 방법을 잘 모르겠어요. 좋은 장소 (잘 쓰여진) 형식의 서명처럼 간단 할 수도 있습니다.

무슨 일이 있었는지 알아 내려고하는 동안, 나는 (나에게 쓸모없는) 비 모나드 버전을 쓸 수 있지만 그것은 컴파일 :

gm :: (MVector v r, PrimMonad s, Num r) => DimFun v s r 
gm = error "" 

g :: forall v r m . (Vector v r, Num r) => v r -> v r 
g = runFun (gm :: forall s . (PrimMonad s) => DimFun (Mutable v) s r) 

이 나 일을하게 위의 this question와 관련된 오류 사전은 갈 곳이 없지만 어둠 속에서 그저 찌르는 것입니다.

+0

이중 게시를 한 것처럼 보입니다. 이것은 아마 삭제되어야하고 대답은 여기에 있습니다 : http://stackoverflow.com/questions/24744294/pattern-matching-on-rank-2-type – jberryman

+0

@jberryman이 두 질문의 문제점은 관련이 있습니다. 코드의 일부 하위 집합이 실제로 동일 함에도 불구하고). 그것이 내가 두 가지 질문으로 게시 한 이유입니다. – crockeea

+0

범위가 지정된 유형 변수를 사용하여 첫 번째 인수의 유형을 수정합니다. 또한'forall'을'runFun'을위한 전역 범위로 분해 해보십시오. – nomen

답변

4

DimFun 데이터 형식 내에서 PrimMonad 제약 조건을 이동하는 것이 한 가지 해결책입니다.

data DimFun v r = DimFun 
    { dim :: Int 
    , func :: forall s . PrimMonad s => v (PrimState s) r -> s() 
    } 

코드의 나머지는, DimFun에서 s 매개 변수를 제거하고 그대로 컴파일 : 당신에게 무서운 보일 수 데이터 유형에 클래스 제약 조건을 이동

runFun :: Vector v r => DimFun (Mutable v) r -> v r -> v r 
runFun = ... 

evalFun :: (PrimMonad s, MVector v r) => DimFun v r -> v (PrimState s) r -> s() 
evalFun = ... 

fm :: (MVector v r, Num r, Monad m) => m (DimFun v r) 
fm = ... 

f :: (Vector v r, Num r, Monad m) => m (v r -> v r) 
f = liftM runFun fm 

, 그러나 현실에서, 당신이 이미 어쨌든 클래스 제약이있었습니다. PrimStatePrimMonad의 관련 유형 제품군이므로 v (PrimState s) r을 생성하거나 사용하려면 PrimMonad 제약 조건이 필요합니다.

그럼에도 불구하고 그것을 피하려면 뭔가 유형을 변경해야합니다. 당신이 illtyped되어있는 기능, (ImpredictiveTypes을 필요로하는) ​​다음 사항을 고려 이유를 보려면 :

fm :: (MVector v r, PrimMonad s, Num r, Monad m) => m (DimFun v s r) 
fm = error "" 

g :: (Vector v r, Monad m) 
    => m (forall s . PrimMonad s => DimFun (Mutable v) s r) -> m (v r -> v r) 
g = liftM runFun 

을 그것은 왜 g fm이 illtyped되어 삭제해야합니다 gforall s . PrimMonad s => 내부 m 무언가를 기대하다 fm의 경우는 해당되지 않습니다. 다음과 같은 유형의 함수를 작성해야합니다.

fm' :: (MVector v r, Monad m, Num r) => m (forall s . PrimMonad s => DimFun v s r) 
fm' = error "" 

f :: forall v r m . (Vector v r, Num r, Monad m) => m (v r -> v r) 
f = g fm' 
+0

두 가지 모두 훌륭한 솔루션입니다. 나는 그것이 내가해야 할 필요가있는 것이 더 분명했으면 좋겠다. – crockeea

+0

이것 역시 [이 질문에] 답합니다 (http://stackoverflow.com/questions/24744294/pattern-matching-on-rank-2-type). 왜냐하면 더 이상 순위 2 유형의 패턴 매치가 필요하지 않기 때문입니다. 내가 물을 수있는 유일한 다른 점은 이것이 미래에해야 할 일이라는 것을 어떻게 알아야하는지에 대한 팁입니다. 데이터 대신에 순위 2 유형을 선호해야하는 이유는 무엇입니까? – crockeea

+1

필자는 항상 예측할 수없는 유형의 데이터 유형에서 보편적으로 정량화 된 필드를 선택해야한다고 생각합니다. 예측할 수없는 유형의 경우 정확한 유형을 알려주는 것이 거의 항상 쉬운 일이 아니며 알 수 있듯이 올바른 유형과 잘못된 유형의 차이는 매우 작습니다. 더 중요한 것은, typechecker는 당신에게 아무 소용이 없다. 왜냐하면 그것은 예측할 수없는 타입을 추론 할 수 없기 때문에 타입 에러가 끔찍할 것이다. – user2407038