2013-04-05 49 views
5

我構建了一個函數,用於使用ST-Monad和非盒裝STArrays(STUArray)查找矩陣的行列式。該類型的矩陣如下:使用STUArray找不到功能的合適簽名(GHC也不能)

newtype Matrix e = Matrix (Array Int (UArray Int e)) 

即,包含含有元素不可改變裝箱陣列的不可變陣列。這將要求我將Predicate IArray UArray e添加到處理Matrix的函數中,這又需要FlexibleContexts。好的,完成了。

用來計算行列式的函數具有以下特徵:

detST :: (IArray UArray e, MArray (STUArray s) e (ST s), 
      Num e, Eq e, Division e) 
    => Array Int (UArray Int e) -> ST s e 

我需要還添加謂詞MArray (STUArray s) e (ST s)因爲內部的陣列被轉換成可變陣列(外盒裝,內裝箱) 。

此功能可用於像這樣:

main = do 
    let [email protected](Matrix x) = matrix [ [1,-2,3,234] 
           , [5,2,3,-3] 
           , [7,18,3,40] 
           , [2,9,71,0] ] 
     d = runST (detST x) :: Int -- needed for type check, ambiguous otherwise 

print d 

工程,細。但看看它有多醜!當然,我不想放棄Matrix的內部結構(至少不會超過我的函數所附帶的謂詞已經使我)。我想定義以下功能:

det :: Matrix e -> e 

而我不能。

我想沒有一個適當的簽名:

det (Matrix arr) = runST (detST arr) 

失敗。公平的,我會讓我的大腦工作:detST要求IArray UArray e, MArray (STUArray s) e (ST s), Num e, Eq e, Division edet也是這樣,不是嗎?

det :: (IArray UArray e, MArray (STUArray s) e (ST s), 
      Num e, Eq e, Division e) => Matrix e -> e 

失敗。但我不知道如何。該GHC(7.4.2)給我的信息是:

Could not deduce (MArray (STUArray s) t (ST s)) 
    arising from a use of `detST' 

但確切項是謂詞!

GHC提示:

add (MArray (STUArray s) t (ST s)) to the context of 
    a type expected by the context: ST s t 
    or the inferred type of 
    det :: (Eq t, Num t, IArray UArray t, Division t) => Matrix t -> t 
or add an instance declaration for (MArray (STUArray s) t (ST s)) 

好。至於我的理解,我已經完成了第一件事。此外,還存在一個實例(MArray ...)(否則,我怎麼能在main ?!中成功使用它)。

我不確定這裏有什麼問題。我相信它與s中的「隱藏」ST狀態有關,並且detST的s是ss中的s會是det,但我不知道如何爲此寫入類型。

什麼是det的正確定義 - 爲什麼?!

該程序沒有det編譯罰款僅使用FlexibleContexts,沒有警告與-Wall。完整的源代碼可以在as a gist here

+1

開始 - 爲什麼不只是使用UArray索引(Int,Int)而不是數組數組? – 2013-04-05 07:54:56

+0

這樣我就可以輕鬆切換行。無論如何,這個程序當然還有其他可能的版本。但是我想知道爲什麼我不能定義這個特定的功能以及它有什麼問題。 – scravy 2013-04-05 07:56:18

+0

你能告訴我們'detST'的定義,以便我們可以測試你的代碼嗎?我不太明白爲什麼它需要在ST中。 – 2013-04-05 08:01:53

回答

4

我設法得到這種利用基岡麥卡利斯特in this article描述的伎倆工作:

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

data Evidence s e where 
    Evidence :: (MArray (STUArray s) e (ST s)) => Evidence s e 

data ElemType e = ElemType (forall s. Evidence s e) 

det :: forall e . (IArray UArray e, Num e, Eq e, Division e) 
     => ElemType e -> Matrix e -> e 
det (ElemType e) mat = runST (f e mat) 
    where 
    f :: Evidence s e -> Matrix e -> ST s e 
    f Evidence (Matrix arr) = detST arr 

用法:

main :: IO() 
main = do 
    let m = matrix [ [1,-2,3,234] 
        , [5,2,3,-3] 
        , [7,18,3,40] 
        , [2,9,71,0] ] 
    print $ det (ElemType Evidence) (m :: Matrix Int) 

問題因缺乏上位約束莖 - runST有鍵入(forall s. ST s a) -> a,因此您需要一個約束條件,如GH36不支持的約束條件forall s . MArray (STUArray s) e (ST s)。這個技巧可以讓你說服類型檢查器約束實際存在。在上面鏈接的文章中可以更深入地討論這個問題。