【问题标题】:Trouble deducing the Read type constraint无法推断读取类型约束
【发布时间】:2020-07-30 03:28:23
【问题描述】:

考虑一个类型

data MyBool a = TRUE | FALSE 

请注意,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)]

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

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

【问题讨论】:

    标签: haskell types functional-programming


    【解决方案1】:

    在标准 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)]
    

    如果您想在没有语言扩展的情况下执行此操作,可以使用辅助函数,类似于为什么 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)
    

    【讨论】:

    • 哦,好的!我不知道。有没有办法在没有语言扩展的情况下做到这一点?
    • @user1892304 不要害怕打开扩展程序;它们中的大多数都是良性的,并且被 Haskell 社区大量使用。特别是,ScopedTypeVariables 应该默认打开。可以说,最初的 Haskell 报告在将两个 a 视为不同的类型变量时做出了错误的选择,并且扩展“修复”了该缺陷(即使它需要 forall)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-23
    • 1970-01-01
    • 1970-01-01
    • 2016-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多