Jam*_*ham 0 haskell overlapping-instances
如果我可以将Monads视为Nums(当然适用的话),我会有一些代码更清晰.足够轻松完成:
{-# LANGUAGE FlexibleInstances #-}
import Control.Monad (liftM, liftM2)
import Data.Char (digitToInt)
instance (Monad m, Num a) => Num (m a) where
(+) = liftM2 (+)
(-) = liftM2 (-)
(*) = liftM2 (*)
abs = liftM abs
signum = liftM signum
fromInteger = return . fromInteger
square :: (Monad m, Num a) => m a -> m a
square x = x * x
-- Prints "Just 9", as expected
main = putStrLn $ show $ square $ Just 3
Run Code Online (Sandbox Code Playgroud)
但是当我将以下函数添加到文件中时...
digitToNum :: (Num a) => Char -> a
digitToNum = fromIntegral . digitToInt
Run Code Online (Sandbox Code Playgroud)
...我收到以下错误:
monadNumTest.hs:15:14:
Overlapping instances for Num (m a)
arising from a use of `*'
Matching instances:
instance (Monad m, Num a) => Num (m a)
-- Defined at monadNumTest.hs:6:10
instance Integral a => Num (GHC.Real.Ratio a)
-- Defined in `GHC.Real'
(The choice depends on the instantiation of `m, a'
To pick the first instance above, use -XIncoherentInstances
when compiling the other instance declarations)
In the expression: x * x
In an equation for `square': square x = x * x
Run Code Online (Sandbox Code Playgroud)
这对我来说没有意义,因为(1)digitToNum从未被调用过,(2)Ratio不是a Monad.所以我不确定这是一个什么问题或为什么这是一个问题.任何有关这方面的提示将不胜感激.
这是GHC 7.4.2,使用Haskell Platform 2012.4.0.0.
这里的关键问题是haskell的一个原则,即编写其他实例不应该改变现有代码的操作.这增加了haskell代码的健壮性,因为如果依赖的模块添加新实例,代码将不会中断或具有不同的行为.
因此,在选择可用于类型的实例时,Haskell不会考虑实例的上下文.例如,在匹配检查类型是否与instance (Monad m, Num a) => Num (m a)类的实例匹配时Num,它只会检查它是否匹配m a.这是因为任何类型以后都可以成为类的实例,并且如果实例选择使用上下文信息,则添加该实例将改变现有程序的操作.
例如,没有什么能阻止在您的模块或您依赖的模块中添加以下代码:
instance Monad Ratio where
return = undefined
(>>=) = undefined
Run Code Online (Sandbox Code Playgroud)
当然,这样的例子是无用的,但是haskell无法判断这一点.它也可能有一个有用的定义Monad为Ratio(我没有看过成).
总之,你要做的不是一个好主意.您可以使用OverlappingInstances和停止这些限制IncoherentInstances,但由于上述原因,大多数haskell程序员不建议将这些标志用于主流.
| 归档时间: |
|
| 查看次数: |
294 次 |
| 最近记录: |