2014-07-14 14 views
5

Dưới đây là các mã:Sử dụng một monadic rank-2 loại

{-# 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)) 

Điều này dẫn đến lỗi:

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 

Tuy nhiên, tôi không chắc chắn làm thế nào để sửa chữa hoặc chẩn đoán vấn đề. Nó có thể đơn giản như một chữ ký loại tốt (và được viết tốt).

Trong khi cố gắng tìm ra những gì đang diễn ra, tôi viết một phiên bản không monadic (vô ích cho tôi), nhưng nó biên dịch:

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) 

Điều này làm cho tôi điều các lỗi trên có liên quan đến this question nơi không có chỗ cho từ điển để đi, nhưng đó thực sự chỉ là một đâm trong bóng tối.

+0

Có vẻ như bạn có thể đã thực hiện một bài đăng kép. Điều này có lẽ nên được xóa và câu trả lời đi ở đây: http://stackoverflow.com/questions/24744294/pattern-matching-on-rank-2-type – jberryman

+0

@jberryman Nó không rõ ràng với tôi rằng vấn đề trong hai câu hỏi này có liên quan (mặc dù một số tập hợp con của mã thực tế là giống nhau). Đó là lý do tôi đăng hai câu hỏi. – crockeea

+0

Sử dụng các biến kiểu phạm vi để sửa loại đối số đầu tiên. Ngoài ra, hãy thử bao thanh toán 'forall' ra phạm vi toàn cục trong loại cho' runFun'. – nomen

Trả lời

4

Một giải pháp là di chuyển ràng buộc PrimMonad bên trong kiểu dữ liệu DimFun.

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

Phần còn lại của mã của bạn biên dịch như-là, loại bỏ các s tham số từ DimFun:

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 

Di chuyển khó khăn lớp thành các kiểu dữ liệu có thể có vẻ đáng sợ đối với bạn, nhưng trong thực tế, bạn đã đã có sự ràng buộc của lớp ở đó. PrimState là họ nhóm có liên quan là PrimMonad, do đó, để sản xuất hoặc tiêu thụ v (PrimState s) r, bạn cần giới hạn PrimMonad.

Nếu bạn muốn tránh nó, bạn sẽ phải thay đổi loại thứ gì đó. Để xem lý do tại sao các chức năng bạn có được illtyped, hãy xem xét những điều sau đây (mà đòi hỏi 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 

Nên xóa tại sao g fm được illtyped: g hy vọng một cái gì đó nơi forall s . PrimMonad s =>bên các m, đó là không phải là trường hợp của fm. Bạn sẽ phải viết một chức năng của loại:

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

Cả hai giải pháp tuyệt vời. Tôi chỉ ước rằng rõ ràng hơn đó là những gì tôi cần làm! – crockeea

+0

Điều này cũng trả lời [câu hỏi này] (http://stackoverflow.com/questions/24744294/pattern-matching-on-rank-2-type), vì tôi không còn cần phải khớp mẫu trên một loại cấp bậc 2. Điều duy nhất tôi có thể hỏi là một mẹo về cách tôi nên biết đây là điều phải làm trong tương lai. Tại sao tôi nên chọn loại xếp hạng 2 bên trong dữ liệu thay vì trên dữ liệu? – crockeea

+1

Theo ý kiến ​​của tôi, bạn nên luôn luôn chọn các trường phổ biến định lượng trong các kiểu dữ liệu trên các kiểu không thể đoán trước. Với các kiểu không đoán trước, hầu như không phải lúc nào cũng dễ dàng biết được loại chính xác nào, và như bạn có thể thấy, sự khác biệt giữa loại chính xác và không chính xác thường rất nhỏ. Quan trọng hơn, các typechecker là không sử dụng cho bạn, vì nó không thể suy ra các loại không dự đoán, và loại lỗi bạn nhận được sẽ là khủng khiếp. – user2407038

Các vấn đề liên quan