【问题标题】:Constraining the return type to a Context将返回类型限制为 Context
【发布时间】:2011-04-19 11:29:14
【问题描述】:

这是我目前的尝试:

module Main where

data FooT = One | Two deriving (Show, Read)
{-
That is what I want
foo :: (Show a, Read a) => a
foo = One
-}

--class Footable (Show a, Read a) => a where
class Footable a where
  --foo2 :: (Show a, Read a) => a
  foo2 :: a

instance Footable FooT where
  foo2 = One

-- test = print foo2

我想编译测试。我认为问题不在于普遍量化。 ghc 说 a 是一个“严格类型变量”editrigid 类型变量),但我并不真正理解这是什么。这个问题好像和this有关

编辑

正如我在@sepp2k 的评论中所写,这可能与存在类型有关,但我偶然发现了一种奇怪的行为:

确实编译:

{-# LANGUAGE OverlappingInstances, FlexibleInstances, OverlappingInstances,
UndecidableInstances, MonomorphismRestriction, PolymorphicComponents #-}
{-# OPTIONS_GHC -fno-monomorphism-restriction #-}

module Main where

    class (Num a) => Numable a where
      foo2 :: a

    instance (Num a) => Numable a where
      foo2 = 1

    instance Numable Int where
      foo2 = 2

    instance Numable Integer where
      foo2 = 3

    --test = foo2 + foo2 -- This does NOT compile (ambiguous a) 
    test = (foo2::Integer) + foo2 --this works

但这不是(`a' 是刚性类型变量消息)

{-# LANGUAGE OverlappingInstances, FlexibleInstances, OverlappingInstances,
UndecidableInstances, MonomorphismRestriction, PolymorphicComponents #-}
{-# OPTIONS_GHC -fno-monomorphism-restriction #-}

module Main where

    data FooT = One | Two deriving (Show, Read)
    data BarT = Ten deriving (Show, Read)

    class (Show a, Read a) => Footable a where
      foo2 :: a

    instance (Show a, Read a) => Footable a where
      foo2 = Ten

    instance Footable FooT where
      foo2 = One

    main = print foo2

之所以如此,是因为 1 :: (Num t) => t。我可以这样定义一些东西(类型构造函数,consts 不知道)吗?

【问题讨论】:

  • 反引号不能格式化多行代码。您必须缩进四个空格(或使用代码按钮或 Ctrl-K)。
  • 和撇号与配色方案混淆。不过现在好了。
  • 您应该真正开始发布整个错误消息。消息的重要部分是“无法匹配预期的类型a' against inferred type BarT”,而不是“a 是刚性类型变量......”(它没有描述错误 - 它只告诉你 a 来自哪里)。

标签: haskell typeclass


【解决方案1】:

当我取消注释 test 的定义并尝试编译您的代码时,我得到“模糊类型变量”。与严格无关。要理解为什么这是模棱两可的考虑这个:

module Main where

data FooT = One | Two deriving (Show, Read)
data BarT = Three | Four deriving Show

class Footable a where
  foo2 :: a

instance Footable FooT where
  foo2 = One

instance Footable BarT where
  foo2 = Three

main = print foo2  -- Should this print One or Three?

当然,在您的代码中只有一个 Footable 实例,因此 Haskell 理论上可以推断您想要使用为 FooT 定义的 foo2,因为这是范围内的唯一实例。但是,如果这样做了,代码会在您导入恰好定义另一个 Footable 实例的模块时中断,因此 haskell 不会这样做。

要解决您的问题,您需要使用其类型注释 foo2,如下所示:

module Main where

data FooT = One | Two deriving (Show, Read)

class Footable a where
  foo2 :: a

instance Footable FooT where
  foo2 = One

main = print (foo2 :: FooT)

要求所有 Footables 都是 Show 和 Read 的实例,只需执行以下操作:

class (Show a, Read a) => Footable a where
  foo2 :: a

就像您在 cmets 中所做的那样,但没有在 foo2 的签名中再次指定约束。

【讨论】:

  • 我的想法是,如果我以这种方式约束 foo foo :: (Show a, Read a) => a 我可以在不违反类型安全的情况下返回各种类型。 (取消注释函数 foo 时会弹出“严格类型变量”)。我的班级Footable是解决问题的尝试。我需要的是存在类型或类型族。
  • 当您执行main = print 3 时,它会将3 专门化为Integer 类型(即使唯一需要的是(Num a, Show a))。可能有一些方法可以定义“默认值”
  • @ony:没有办法为用户定义的类型类定义默认值。
【解决方案2】:

正如 sepp2k 所说,Ghc 无法猜测 foo2 的返回类型。做约束它(这是你的问题的标题)添加一个内联类型签名。

test = print (foo2 :: FooT)

【讨论】:

  • ::FooT 不限制上下文,但将 foo2 声明为 FooT 类型
  • 这是我们想要的,不是吗?
猜你喜欢
  • 2010-12-26
  • 2020-05-14
  • 1970-01-01
  • 2021-02-05
  • 2010-09-27
  • 1970-01-01
  • 2014-12-28
  • 1970-01-01
相关资源
最近更新 更多