2014-02-21 73 views
2

我有這樣的單態代碼:約束類型變量的具體類型

import Data.Array.MArray 
import Data.Array.IO (IOUArray) 
import Data.Ix (Ix) 

push :: IOUArray Int Int -> Int -> [Int] -> IO Int 
push stack top [] = return top 
push stack top (k:ks) = do 
    v <- readArray stack k 
    if v >= 0 then push stack top ks 
      else do writeArray stack k top 
        push stack k ks 

push一個完全多態的簽名是:

push :: (MArray a e m, Ix e, Num e) => a e e -> e -> [e] -> m e 

但是我試着寫這部分多態特徵:

push :: MArray a e m => a Int e -> Int -> [Int] -> m Int 
push :: MArray a e m => a Int Int -> Int -> [Int] -> m Int 
push :: MArray a Int m => a Int Int -> Int -> [Int] -> m Int 
push :: (MArray a e m, e ~ Int) => a e e -> e -> [e] -> m e 

我得到的錯誤如can't deduce (e ~ Int)can't deduce (MArray a Int m) ...Non type-variable argument in constraintIllegal equational constraint

有沒有辦法約束的第一個簽名的類型變量e的具體類型一樣Int

回答

5

第三個標誌性作品,如果你能FlexibleContexts(如錯誤提示):

{-# LANGUAGE FlexibleContexts #-} 
import Data.Array.MArray 
import Data.Array.IO (IOUArray) 
import Data.Ix (Ix) 

push :: MArray a Int m => a Int Int -> Int -> [Int] -> m Int 
-- push :: IOUArray Int Int -> Int -> [Int] -> IO Int 
push stack top [] = return top 
push stack top (k:ks) = do 
    v <- readArray stack k 
    if v >= 0 then push stack top ks 
      else do writeArray stack k top 
        push stack k ks 

有對哈斯克爾總理wiki的some discussion of this extension

第四簽名與TypeFamilies工作,使e ~ Int約束:

{-# LANGUAGE TypeFamilies #-} 
import Data.Array.MArray 
import Data.Array.IO (IOUArray) 
import Data.Ix (Ix) 

push :: (MArray a e m, e ~ Int) => a e e -> e -> [e] -> m e 
-- push :: IOUArray Int Int -> Int -> [Int] -> IO Int 
push stack top [] = return top 
push stack top (k:ks) = do 
    v <- readArray stack k 
    if v >= 0 then push stack top ks 
      else do writeArray stack k top 
        push stack k ks 

在這種特殊情況下,我認爲這正是在呼籲環境與FlexibleContexts其他工作簽名的類型檢查的效果相同,但一般而言,具有相等約束的類型變量與具體類型並不完全相同。

3

的第一個簽名

push :: MArray a e m => a Int e -> Int -> [Int] -> m Int 

,因爲你正在閱讀其類型e數組元素v <- readArray stack k不工作,但後來把它比作0,這是一個IntInteger(編輯:任何真正的Num )。

第二簽名

push :: MArray a e m => a Int Int -> Int -> [Int] -> m Int 

不工作,因爲你說a e mMArray一個實例,但隨後嘗試使用一個a Int Int。 GHC會嘗試將所需約束與給定約束統一起來,因此它會嘗試將eInt相匹配。

Ganesh的回答解決了其他兩個簽名。

+1

'0'不只是'Int'或'Integer',它可以是任何'Num a => a'。 –