Haskell:“因使用函数而产生的模糊类型变量”,其中所说的变量实际上并不重要

时间:2018-11-08 14:59:04

标签: haskell ghc

考虑以下功能:

foo :: Show a => Maybe a -> [Char] 
foo (Just x) = show x 
foo Nothing = "Nothing"

然后我尝试使用此功能:

bar :: [Char]
bar = foo Nothing

已传递给foo的参数的类型为Maybe a,其中未指定a,实际上我们不在乎a,因为我们使用fooNothing的情况。但是GHC声称提供了具体的类型:

  

使用a0引起的模棱两可的类型变量foo
  阻止约束(Show a0)被解决。可能   修复:使用类型注释来指定a0应该是什么。

GHC提示指定类型。因此,我看到的唯一解决方法是创建一个伪类型,该类型具有Show类型类的实例:

{-# LANGUAGE EmptyDataDecls, KindSignatures #-}
{-# OPTIONS_GHC -fno-warn-missing-methods #-}

data Dummy :: *

instance Show Dummy

bar :: [Char]
bar = foo (Nothing :: Maybe Dummy)

foo :: Show a => Maybe a -> [Char]
foo (Just x) = show x
foo Nothing = "Nothing"

它可以工作,但是看起来非常简单。但是,我不喜欢这种解决方案的真正原因是,出于我的目的,该代码是从某些元数据自动生成的,该元数据不提供有关必须将哪种特定的多态类型指定为Dummy的信息(可能是具有多个参数的用户数据类型)。所以我想知道,有没有办法告诉GHC,如果未指定类型,则此类型无关紧要?

2 个答案:

答案 0 :(得分:8)

“无关紧要”是实例的属性,而ghc不会自省这样的实例。对于某些类型,这确实很重要。 Show的{​​{1}}实例取决于类型[a],即使列表为空。检查ashow ([] :: [Char])的结果。

但是所有这些都放在一边。事实是,类型是在编译时确定的,而值是在运行时确定的。您提出了一种情况,其中类型变量仅对某些输入值无关紧要。在这种情况下,类型变量仍然很重要,因为它们在其他情况下控制行为。

您将必须正确解析不明确的类型,因为ghc知道使用哪种代码。有一些技术可以很方便地做到这一点,例如使用ScopedTypeVariables扩展,但是如果没有更具代表性的代码,很难推荐一种方法。我能说的最重要的事情是,它确实很重要,因为实例选择是在编译时完成的,而且早在看到值之前。

答案 1 :(得分:4)

类型检查器不知道foo对它的参数有什么作用,特别是不知道实际上不会使用Nothing。但是确实知道参数必须具有类型Show a => Maybe a,并且Nothing具有更一般的类型Maybe a。由您自己决定,在调用foo时提供一个狭窄的参数。

无需定义新的虚拟类型。任何具有Show实例的现有类型都可以。

bar :: [Char]
bar = foo (Nothing :: Maybe ())