尝试返回可扩展记录时出现编译类型错误

萨拉瓦南

我已经创建了一个可扩展的记录类型,我怎样才能返回最小的基本类型而不会出现编译器抛出错误。

我有一个类型的记录,

type SectionContent r = 
   { titleText :: String 
   , subTitleText :: String
   , ....
   | r 
   }

我正在扩展它,比如

type MyConfig = 
    { section1 : SectionContent ()
    , section2 : SectionContent (someContent :: {...})
    ..
    }

当我尝试像这样访问我的代码时,

  -- This is inside another function & I have access to config
  currenScreenConfig :: forall r. SectionContent r 
  currenScreenConfig = if predicate 
                         then config.section1
                         else config.section2 

它抛出错误,

Could not match type
                                                 
    ( someContent :: {...})                                            
                                                 
  with type
      
    r0  
.....
where r0 is a rigid type variable
    bound at ...
  ....

刚性类型在这里到底是什么意思?

费奥多尔·索伊金

这是关于谁可以选择通用参数的经典混淆。

forall r.当您访问(或“引用”或“使用”)其类型前面有 a 的值时,您可以选择是什么r并且无论谁实现了该值,都必须使它与r您选择的值一起使用。不知道你会提前选择什么。

换句话说:选择类型参数的是函数的调用者,而不是实现者

因此,currenScreenConfig稍后调用您的函数的人可能会决定选择r ~ ( foo :: String ). 然后你的函数必须返回一个记录SectionContent ( foo :: String )

另一个调用者,在不同的地方,可能会选择( bar :: Int ),然后你的函数必须返回一个记录SectionContent ( bar :: Int )

你看到没有办法实现这样的功能吗?


现在,如果你想返回 just SectionContent (),那么函数的类型应该是:

currenScreenConfig :: SectionContent ()

但是当然你不能 return config.section2,因为它有不同的类型。


有一些方法可以“修剪”记录(即丢弃不需要的字段)。其中一种方法是包中pick函数record-extra您可以像这样使用它:

currenScreenConfig :: SectionContent ()
currenScreenConfig = if predicate then config.section1 else pick config.section2

但是,我鼓励您改用更自然的模型。如果各种屏幕内容的“共同”部分通常是这样提取的,那么将其作为一个字段包含而不是合并会更自然:

type SectionContentCommon =
  { titleText :: String 
  , subTitleText :: String
  , ....
  }

type SectionContent r =
  { common :: SectionContentCommon
  | r
  }

type MyConfig = ... same ... 

currenScreenConfig :: SectionContent ()
currenScreenConfig = if predicate then config.section1.common else config.section2.common

使用可扩展记录可能看起来很酷很闪亮,但我强烈建议您考虑一个更直接的模型。相信我:凉爽和闪亮永远不会超过长期维护。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

实现可扩展记录时编译错误

返回通用类类型时出现Java编译错误

为什么在 C# 中尝试使用记录类型时会出现编译错误?

尝试查找文件位置时,出现此错误(需要错误记录、对象或类类型)

为什么在尝试编译代码时出现模棱两可的方法错误?

尝试编译fftw时返回错误

尝试从模板类型列表中删除相邻重复项时出现编译错误

为什么在尝试从模拟返回值时会出现编译时错误?

尝试打开文件时出现类型错误

扩展ApplicationUsers时,尝试访问属性时出现null错误

尝试使用 Citrus - 编译错误:需要返回类型

尝试从联合中提取类型时出现类型错误

尝试编译代码时出现错误127

尝试编译lua文件时出现gcc错误

尝试组合 hamcrest 匹配器时出现编译错误

尝试使用vector <ostringstream>时出现编译错误

为什么在尝试编译时出现“ __CrtGetFileInformationByHandleEx”错误

尝试为Tensorflow编译XLA AOT时出现链接错误

尝试编译Boost项目时,出现以下错误

尝试编译时出现Boost C2064错误

尝试创建菜单时出现编译器错误

尝试从struct打印时出现编译器错误

尝试构建示例代码时出现编译错误

尝试在Windows上创建扩展时出现PostgreSQL错误

尝试在宏扩展中实现特征时出现宏错误

尝试记录json值时出现NaN错误

尝试在Django中更新记录时出现递归错误

尝试从hasMany集合中删除记录时出现错误

尝试添加视图行情记录时出现drupal错误500