你有以下的最普遍的類型:
createCustomeInitializedArray :: IA.IArray a Int => ST s (a Int Int)
這有一個類型類的約束IA.IArray a Int
在裏面。實際上這有點棘手,因爲它將類型類在第二個參數中部分應用於固定類型。 Haskell98不允許這樣;如果啓用-XFlexibleContexts
擴展名,GHC會執行此操作。除此之外,這顯然是一種多態類型,但由於createCustomeInitializedArray
沒有(顯式)參數,因此編譯器希望通過dreaded monomorphism restriction將其設置爲。即它拒絕推斷多態類型,你需要用明確的簽名來請求它。採用頂級的簽名是一個非常好的主意,無論如何,這樣做的:
{-# LANGUAGE FlexibleContexts #-}
createCustomeInitializedArray :: IA.IArray a Int => ST s (a Int Int)
createCustomeInitializedArray = do
arr <- newArray (0,10) 0 :: ST s (STArray s Int Int)
-- ...
iarr <- freeze arr
return iarr
我想補充一點,你有newArray (0,10) 0
這個地方簽名不辦得是什麼樣子:Haskell的類型變量不範圍,所以s
那裏不知道s
從邊遠國家;以下是更忠實於編譯器看到的是:
createCustomeInitializedArray :: IA.IArray a Int => ST s (a Int Int)
createCustomeInitializedArray = do
arr <- newArray (0,10) 0 :: ST s₁ (STArray s₁ Int Int)
-- ...
因此,它使當地的行動從外部s
完全獨立的多態,只有那麼它實例到該狀態的說法。嗯,在這個特例中這實際上沒有問題,但通常它可能是一個討厭的問題(特別是外層的約束不會傳播到內層)。因此,這是代碼,我建議:
{-# LANGUAGE FlexibleContexts, ScopedTypeVariables, UnicodeSyntax #-}
createCustomeInitializedArray :: ∀ s a . IA.IArray a Int => ST s (a Int Int)
createCustomeInitializedArray = do
arr <- newArray (0,10) 0 :: ST s (STArray s Int Int)
-- ...
iarr <- freeze arr
return iarr
這也可以更簡明地寫一點作爲
arr :: STArray s Int Int <- newArray (0,10) 0
僅添加'iarr < - freeze arr :: ST s(Array Int Int)'不起作用。其他解決方案正在工作 –
正確的,你不可以爲'ST'行爲做一個單形簽名(因爲'runST'是rank-2多態的,所以不會變得無法使用)。 – leftaroundabout