2015-12-13 2 views
1

Названное, вероятно, не ярчайший один, но если честно, я не знаю, что я не знаю :(Метод вызова класса. Неопределенный тип

Существует этот класс Clock:

class Clock c where 
    rate :: c → Double 

data AudRate 
data CtrRate 

И примеры:

instance Clock AudRate where 
    rate _ = 44100 
instance Clock CtrRate where 
    rate _ = 4410 

Моя функция:

burst :: Clock p => Double -> SigFun p() Double 
burst m = proc() -> do 
    burstEnv <- envLineSeg [1,1,0,0] [(m/(rate (undefined :: p))), (1/4410), (m+1/4410) ] -<() 
    noise <- noiseWhite 51 -<() 
    outA -< noise * burstEnv 

GHC говорит мне, что: (г ели (не определено :: р))

Could not deduce (Clock p0) arising from a use of `rate' 
from the context (Clock p) 
    bound by the type signature for 
      burst1 :: Clock p => Double -> SigFun p() Double 
    at Karplus.hs:11:11-49 
The type variable `p0' is ambiguous 

Но такое же выражение используется в исходном коде библиотеки я использую.

outFileHelp :: forall a p. (AudioSample a, Clock p) => 
     ([Double] -> [Double]) --^Post-processing function. 
    -> String    --^Filename to write to. 
    -> Double    --^Duration of the wav in seconds. 
    -> Signal p() a  --^Signal representing the sound. 
    -> IO() 
outFileHelp f filepath dur sf = 
let sr   = rate (undefined :: p) 
    numChannels = numChans (undefined :: a) 
    numSamples = truncate (dur * sr) * numChannels 
    dat   = map (fromSample . (*0.999)) 
        (f (toSamples dur sf)) :: [Int32] 
       -- multiply by 0.999 to avoid wraparound at 1.0 
    array  = listArray (0, numSamples-1) dat 
    aud = Audio { sampleRate = truncate sr, 
       channelNumber = numChannels, 
       sampleData = array } 
in exportFile filepath aud 

Можно ли использовать это выражение в моем коде и сделать GHC его компиляцией? Есть ли расширения?

+0

Кстати, этот способ передачи фантомных аргументов с 'undefined' является рискованным и несколько устаревшим. Я бы написал новый код с ['rate :: Tagged c Double'] (http://hackage.haskell.org/package/tagged-0.8.2/docs/Data-Tagged.html). Это тоже немного неудобно, но определенно лучше. – leftaroundabout

ответ

5

Проблема в том, что переменные типа по умолчанию привязаны только к одной сигнатуре. То есть когда вы используете p в своей сигнатуре функции, компилятор не свяжет это вообще с undefined :: p, которые вы затем используете в определении. Скорее, он подумает “ undefined другого типа, который также упоминается как p “.

К счастью, GHC может переменных типа сфера в целом определения функции:

{-# LANGUAGE ScopedTypeVariables #-} 

burst :: ∀ p . Clock p => Double -> SigFun p() Double 
burst m = proc() -> do 
    burstEnv <- envLineSeg [1,1,0,0] [(m/(rate (undefined :: p))), (1/4410), (m+1/4410) ] -<() 
    noise <- noiseWhite 51 -<() 
    outA -< noise * burstEnv 

Обратите внимание, что ∀ p является обязательным (forall a p. (AudioSample a, Clock p)) в примере коде), в противном случае ScopedTypeVariables просто не относится к этому функция.

Смежные вопросы