在下面的代码中,ghc抱怨模棱两可。我假设它是因为类型类是开放的(外部代码可以定义新实例并且实际上使这个模糊不清)。
如果我能以某种方式关闭 Indexable
类型类,那么这足以使这个想法成为实现基本关联类型的有效方法吗?
问题更多是关于类型推断的理论方面,而不是关于如何让它在Haskell中工作。这个问题是否存在这样一个系统的理论问题,这个系统不能对下面的t1
进行推理?是否允许封闭类型足以明确推断t1
?
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
class Indexable a where
instance Indexable (String, Int, Char) where
instance Indexable ([(String, a)], String, a) where
test1 :: Indexable (a,b,c) => a -> b -> c
test1 x y = undefined
t1 = test1 "hi" 3 == 'c'
main = return ()
----------------------------------------------------------------
-- indexable.hs:14:6: --
-- No instance for (Indexable ([Char], b0, Char)) --
-- arising from a use of ‘test1’ --
-- The type variable ‘b0’ is ambiguous --
-- Note: there is a potential instance available: --
-- instance Indexable (String, Int, Char) --
-- -- Defined at indexable.hs:8:10 --
-- In the first argument of ‘(==)’, namely ‘test1 "hi" 3’ --
-- In the expression: test1 "hi" 3 == 'c' --
-- In an equation for ‘t1’: t1 = test1 "hi" 3 == 'c' --
-- --
-- indexable.hs:14:17: --
-- No instance for (Num b0) arising from the literal ‘3’ --
-- The type variable ‘b0’ is ambiguous --
-- Note: there are several potential instances: --
-- instance Num Double -- Defined in ‘GHC.Float’ --
-- instance Num Float -- Defined in ‘GHC.Float’ --
-- instance Integral a => Num (GHC.Real.Ratio a) --
-- -- Defined in ‘GHC.Real’ --
-- ...plus three others --
-- In the second argument of ‘test1’, namely ‘3’ --
-- In the first argument of ‘(==)’, namely ‘test1 "hi" 3’ --
-- In the expression: test1 "hi" 3 == 'c' --
----------------------------------------------------------------
答案 0 :(得分:4)
此错误是由可怕的monomorphism restriction引起的。使用NoMonomorphismRestriction
禁用它。
{-# LANGUAGE NoMonomorphismRestriction #-}
此问题是您应该使用MultiParamTypeClasses
和newtype
的一个很好的示例。
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE MultiParamTypeClasses #-}
import Data.Maybe
class Indexable k v c where
at :: c -> k -> Maybe v
普通列表为Indexable
Int
。
instance Indexable Int a [a] where
c `at` k = listToMaybe . drop k $ c
具有关联列表特殊含义的列表如果包含在Indexable
中,则可以以不同的方式轻松newtype
。
newtype Assoc k v = Assoc {getAssoc :: [(k, v)]}
instance (Eq k) => Indexable k v (Assoc k v) where
c `at` k = fmap snd . listToMaybe . filter ((== k) . fst) . getAssoc $ c
使用NoMonomorphismRestriction
或显式签名,测试剪切将编译。
-- t1 :: Indexable Int v [Char] => Maybe v
t1 = "hi" `at` (3 :: Int)
使用Indexable
或FunctionalDependencies
来帮助编译器推断所涉及的类型,可以进一步改进TypeFamilies
类。
{-# LANGUAGE FunctionalDependencies #-}
class Indexable k v c | c -> k, c -> v where
at :: c -> k -> Maybe v