无法推断读取类型约束

use*_*304 4 haskell types functional-programming

考虑一个类型

data MyBool a = TRUE | FALSE 
Run Code Online (Sandbox Code Playgroud)

请注意,MyBool a这并不真正取决于a,但让我们这样做只是为了好玩。

现在想象我想定义一个函数isParsable :: (Read a) => String -> MyBool a来决定给定的字符串是否可解析为a并将结果输出为MyBool a.

当然,我想写:

isParsable :: (Read a) => String -> MyBool a
isParsable str
 | (null parses) = FALSE
 | (otherwise) = TRUE
     where parses = (reads str)::[(a, String)]
Run Code Online (Sandbox Code Playgroud)

现在这不能编译,但我真的不明白为什么。我不认为这个函数是模棱两可的,因为任何调用isParsable都必须强制选择a并因此确保Read a满足约束,因为它就在类型签名中。此外,该where条款强制reads :: String -> [(a, String)]. 但出于某种原因,GHC 抛出了一个错误。

我在这里误解了什么,有什么方法可以克服这个问题?

Jos*_*ica 5

在标准 Haskell 中,a类型签名中的 与正文中的不同。为了使它们相同,您需要启用ScopedTypeVariables扩展并对其进行明确量化,如下所示:

{-# LANGUAGE ScopedTypeVariables #-}

data MyBool a = TRUE | FALSE

isParsable :: forall a. (Read a) => String -> MyBool a
isParsable str
 | (null parses) = FALSE
 | (otherwise) = TRUE
     where parses = (reads str)::[(a, String)]
Run Code Online (Sandbox Code Playgroud)

如果你想在没有语言扩展的情况下做到这一点,你可以使用一个辅助函数,类似于为什么asTypeOf有用:

data MyBool a = TRUE | FALSE

isParsableHelper :: [(a, String)] -> MyBool a
isParsableHelper parses
 | (null parses) = FALSE
 | (otherwise) = TRUE

isParsable :: (Read a) => String -> MyBool a
isParsable str = (isParsableHelper parses)
     where parses = (reads str)
Run Code Online (Sandbox Code Playgroud)

  • @user1892304 不要害怕打开扩展;其中大多数都是良性的,并且被 Haskell 社区大量使用。特别是,默认情况下应启用“ScopedTypeVariables”。可以说,最初的 Haskell 报告在将两个 `a` 视为不同的类型变量方面做出了错误的选择,而扩展“修复”了该缺陷(即使它需要 `forall`)。 (3认同)