闭合类型是否足以推断相关类型(没有类型族)?

时间:2015-02-25 00:39:35

标签: haskell typeclass associated-types

在下面的代码中,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'                 --
----------------------------------------------------------------

1 个答案:

答案 0 :(得分:4)

此错误是由可怕的monomorphism restriction引起的。使用NoMonomorphismRestriction禁用它。

{-# LANGUAGE NoMonomorphismRestriction #-}

此问题是您应该使用MultiParamTypeClassesnewtype的一个很好的示例。

{-# 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)

使用IndexableFunctionalDependencies来帮助编译器推断所涉及的类型,可以进一步改进TypeFamilies类。

{-# LANGUAGE FunctionalDependencies #-}

class Indexable k v c | c -> k, c -> v where
    at :: c -> k -> Maybe v