将类型变量约束为具体类型

时间:2014-02-21 19:01:34

标签: haskell polymorphism type-variables

我有这个单形代码:

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这样的具体类型?

2 个答案:

答案 0 :(得分: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

Haskell Prime 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的其他工作签名具有完全相同的效果,但通常具有等式约束的类型变量与具体的类型。

答案 1 :(得分:3)

第一个签名

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

不起作用,因为您正在读取类型为v <- readArray stack k的数组元素e,但是将其与0进行比较,即IntInteger(编辑:真的任何Num)。

第二个签名

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

不起作用是因为您说a e mMArray的实例,但后来尝试使用 a Int Int。 GHC尝试使用给定约束统一所需约束,因此它尝试将eInt匹配。

Ganesh的回答解决了其他两个签名。