2014-07-14 7 views
5

Oto kod:Korzystanie z jednowartościowy szeregowych typu 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)) 

Wynika to z błędów:

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 

Jednak nie jestem pewien, jak to naprawić lub zdiagnozować problem. Może to być tak proste, jak dobrze (i dobrze napisany) podpis typu.

Starając się zrozumieć, co się dzieje, piszę wersję non-jednowartościowy (bezużyteczny dla mnie), ale kompiluje:

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) 

To czyni mnie rzeczą błąd powyżej jest związane z this question tam, gdzie nie ma miejsca na słownik, ale to po prostu ukłucie w ciemności.

+0

Wygląda na to, że mogłeś zrobić podwójny wpis. Prawdopodobnie powinno to zostać usunięte i odpowiedzi można znaleźć tutaj: http://stackoverflow.com/questions/24744294/pattern-matching-on-rank-2-type – jberryman

+0

@jberryman Nie jest dla mnie oczywiste, że problemy w tych dwóch kwestiach są powiązane (choć niektóre podzestawy kodu są w rzeczywistości takie same). Dlatego wysłałem jako dwa pytania. – crockeea

+0

Użyj zmiennych typu scoped, aby ustalić typ pierwszego argumentu. Spróbuj także wypróbować opcję 'forall' poza zasięgiem globalnym w typie dla' runFun'. – nomen

Odpowiedz

4

Jednym z rozwiązań jest przeniesienie ograniczenia PrimMonad w typ danych DimFun.

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

Reszta kodu kompiluje jak jest usunięcie parametru s z 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 

Przesuwanie ograniczenia klasy do typu danych może wydawać się przerażające dla ciebie, ale w rzeczywistości, to już w każdym razie miał tam przymus klasy. PrimState jest typem skojarzonej rodziny PrimMonad, więc aby wyprodukować lub zużyć v (PrimState s) r, potrzebujesz ograniczenia PrimMonad.

Jeśli jednak chcesz tego uniknąć, będziesz musiał zmienić typ czegoś. Aby zrozumieć, dlaczego funkcja masz jest illtyped, należy rozważyć następujące kwestie (które wymaga 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 

Należy wyczyszczone dlaczego g fm jest illtyped: g oczekuje czegoś gdzie forall s . PrimMonad s => jest wewnątrzm, który jest nie w przypadku fm. Będziesz musiał napisać funkcję typu:

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

Oba doskonałe rozwiązania. Chciałbym tylko, żeby było bardziej oczywiste, że właśnie to muszę zrobić! – crockeea

+0

To również odpowiada [to pytanie] (http://stackoverflow.com/questions/24744294/pattern-matching-on-rank-2-type), ponieważ nie muszę już dopasowywać wzorca w typie rank-2. Jedyną rzeczą, o którą mógłbym poprosić, to wskazówka, jak powinienem wiedzieć, co należy robić w przyszłości. Dlaczego mam preferować typy rang 2 w danych zamiast w danych? – crockeea

+1

Moim zdaniem, zawsze należy wybierać uniwersalnie kwantyfikowane pola w typach danych nieprzewidywalnych. W przypadku typów nieprzewidywalnych prawie zawsze nie jest łatwo określić, jaki powinien być właściwy typ, a jak widać, różnica pomiędzy typem poprawnym a niepoprawnym jest często bardzo mała. Co ważniejsze, typechecker jest dla ciebie bezużyteczny, ponieważ nie może wywnioskować typu nieprzewidywalnego, a błędy typu, które otrzymujesz, będą okropne. – user2407038

Powiązane problemy