【问题标题】:Are closed type classes enough for inference of associated types (without type families)?封闭类型类是否足以推断关联类型(没有类型族)?
【发布时间】:2023-04-10 05:39:01
【问题描述】:

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

【问题讨论】:

  • 你为什么要这样做?
  • 我也想知道。为什么不使用类型族?
  • 动机:在设计类型系统时提供基本的关联类型功能,但以简单(对于类型检查器)的方式进行。不打算在 Haskell 中使用
  • @dfeuer 更新了问题以澄清并参见上面的评论
  • @sinelaw 知道密钥具有 Num 实例并且 Indexable 已关闭并且唯一可能的密钥是 IntString 并不足以知道密钥必须是Int。您还需要知道Num 永远不会有String 的实例,这意味着Num 也已关闭。或者,您可以告诉您必须使用容器为String 的实例,因为容器不是[(String, a)] 并且知道Indexable 已关闭。根据容器选择实例正是您对fundeps或类型族所做的事情。

标签: haskell typeclass associated-types


【解决方案1】:

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

{-# LANGUAGE NoMonomorphismRestriction #-}

这个问题是你应该使用MultiParamTypeClassesnewtypes 的一个很好的例子。

{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE NoMonomorphismRestriction #-}
{-# LANGUAGE MultiParamTypeClasses #-}

import Data.Maybe

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

一个普通的列表是Indexable by Int

instance Indexable Int a [a] where
    c `at` k = listToMaybe  . drop k $ c

如果将一个具有特殊意义的关联列表包含在newtype 中,它可以很容易地以不同的方式变成Indexable

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 类可以通过使用FunctionalDependenciesTypeFamilies 进一步改进,以帮助编译器推断所涉及的类型。

{-# LANGUAGE FunctionalDependencies #-}

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

【讨论】:

  • 有没有办法在没有fundeps或类型族的情况下推断类型?不一定在 Haskell 中,理论上也是如此
猜你喜欢
  • 1970-01-01
  • 2016-10-28
  • 1970-01-01
  • 2018-07-16
  • 2017-04-10
  • 2018-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多