我使用ST-Monad和非装箱STArrays (STUArray)编写了一个用于找到矩阵行列式的函数。矩阵的类型如下:
newtype Matrix e = Matrix (Array Int (UArray Int e))
即,一个不可变的数组,其中包含不可变的未装箱的数组,包含元素。这将要求我将谓词 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 m@(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 e
,那么 det
也需要,是吗?
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 ...)
(否则,我怎么能在主函数中成功使用它呢?!)。
我不确定这里出了什么问题。我认为这与s
中的“隐藏”ST状态有关,而detST
中的s是与det
中的s不同的另一个s,但我不知道如何为此编写类型。
det
的正确定义是什么 - 为什么?!
没有det
的程序通过只使用FlexibleContexts
编译得很好,在-Wall
下没有警告。完整的源代码可以在此处作为gist找到。
detST
的定义,这样我们就可以测试你的代码了吗?我不太明白为什么它需要在ST
中。 - Mikhail Glushenkov