haskell - 如何强制应用于可强制参数的仿函数

标签 haskell type-conversion

考虑以下 Haskell 代码:

import Data.Coerce

newtype Decorated s a = Decorated a

fancyFunction :: Ctx s => f (Decorated s a) -> r
fancyFunction = ...

instance Ctx s => SomeClass (Decorated s a)

myFunction :: Functor f => f a -> r
myFunction = fancyFunction . fmap coerce

我想通过将 fmap coerce 替换为 coerce 来使 myFunction 更快。基本原理是,coerce 的行为类似于 id,仿函数法则之一是 fmap id = id

我能想到的唯一方法是将 Coercible (f a) (f (Decolated s a)) 添加到上下文中,但它引用的 s 没有在其他任何地方引用。更糟糕的是,如果 a 绑定(bind)在通用类型中,我无法表达该约束。是否有一个约束我可以用 f 来表达,只让我使用 coercef af (装饰 s a )

这是编译器根据 f 是仿函数这一事实自行计算出来的吗?如果是这样,它是否也适用于 bifunctors、traversables 和 bittraverables?

最佳答案

不幸的是,Coercible (f a) (f (Decorated s a))考虑到 GHC 的当前状态,您确实想要在约束中得到什么。现在,事实是sa不出现在其他地方并不是什么好事 - 这意味着 GHC 不知道如何处理它们(它们是模棱两可的)!我不会涉及这个...

<小时/>

取决于role提供给类型构造函数的类型参数 f , Coercible a b可能暗示也可能不暗示Coercible (f a) (f b) 。在这种情况下,我们希望该角色是名义上的 - 但(至少)还没有一种方法可以在约束中表达这一点。为了解释我的意思,请考虑以下两个数据定义:

{-# LANGUAGE TypeFamilies #-}
import Data.Coerce

-- type role of `a` is "representational"
data Data1 a = Data1 a

-- type role of `a` is "nominal"
data Data2 a = Data2 (TypeFunction a)
type family TypeFunction x where
  TypeFunction Bool = Char
  TypeFunction _ = ()

那么,虽然 Coercible a b 确实如此需要Coercible (Data1 a) (Data1 b) ,它需要 Coercible (Data2 a) (Data2 b) 。为了使这一点具体化,请在 GHCi 中加载上述内容,然后尝试:

ghci> newtype MyInt = My Int
ghci> let c1 = coerce :: (Data1 MyInt) -> (Data1 Int)
ghci> let c2 = coerce :: (Data2 MyInt) -> (Data2 Int) -- This doesn't work! 

不幸的是,没有基于内置约束的方法来强制类型变量的角色具有代表性。您可以为此创建自己的类(class),如 Edward Kmett has done ,但 GHC 不会像 Coercible 的类实例那样自动创建其中一些类的实例。是。

这导致了 this trac 票,他们在其中讨论类的可能性 Representational f生成的实例类似于 Coercible其中可能有类似的内容

instance (Representational f, Coercible a b) => Coercible (f a) (f b)

如果这确实是今天的事情,那么您在约束中所需要的就是 Representational f 。此外,正如理查德·艾森伯格在罚单上观察到的那样,我们确实应该能够弄清楚 af a对于任何合理的仿函数都具有代表性作用f 。然后,我们甚至可能不需要 Functor f 之上的任何约束如Representational可能是 Functor 的父类(super class).

Here is a good discussion of the current limitations of roles.

关于haskell - 如何强制应用于可强制参数的仿函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39522041/

相关文章:

通过使用 QuickCheck 生成输入来测试 Parsec 解析器

c# - 将枚举转换为列表

ios - 在 .docx 的 UITextView 中显示文本

sql - 如何将 SQL 表中列的数据类型从整数更改为小数

c# - 为什么 Convert.ChangeType() 不将日期字符串(以 dd/MM/yyyy 格式)转换为日期时间类型?

c++ - 使用std::filesystem, error shows cannot convert int to _Valty

haskell - 无法构造无限类型

haskell - 字节串构建器内部的类型参数是什么?

haskell - 在 Haskell 中循环遍历 Monad

haskell - 可折叠与可遍历