gpt4 book ai didi

haskell - 具有逆变位置变量的存在包装实例

转载 作者:行者123 更新时间:2023-12-02 08:26:17 25 4
gpt4 key购买 nike

我有以下定义:

{-# LANGUAGE ExistentialQuantification #-}

module Test
where

class Named a where
name :: a -> String

data Wrap = forall a . (Named a, Read a) => Wrap (a -> IO ())

我想为 Wrap 编写 Named 实例。下一个不起作用:

instance Named Wrap where
name (Wrap named) =
let a = undefined
_ = named a
in name a

错误:

Could not deduce (Named a0) arising from a use of ‘name’
from the context (Named a, Read a)

但以下工作:

instance Named Wrap where
name (Wrap named) =
let a = read undefined
_ = named a
in name a

我看到的唯一区别是 aread 中处于协变位置,但在 name 中处于逆变位置。为什么一审声明不起作用?

最佳答案

第一个实例不起作用,因为它不会触发单态限制,所以 a 得到一个多态类型,它在 不同 中被实例化,名为 a name a。另一方面,当写a = read undefined时,我们发现a有一个typeclass-restricted类型,所以单态限制开始了,我们必须选择一个特定的类型对于一个;由于 named a 唯一标识此类型,因此选择该类型并且它不会在 name a 中以不同类型实例化。

您可以通过打开 NoMonomorphismRestriction 来验证这是正确的解释,从而导致 read 版本失败。

您可以使用 lambda 而不是 let 来解决这个问题,如下所示:

instance Named Wrap where
name (Wrap named) = (\a -> (\_ -> name a) (named a)) undefined

(一般来说,let x = e in e' 等同于(\x -> e') e,提供x是单态的而不是递归的,我在这里重写了两次。)

但是,如果可能的话,我建议对您的方法进行更认真的修改,以完全避免 undefined 。标准技巧是:

class Named a where
name :: proxy a -> String

proxyForFun :: (a -> IO ()) -> Proxy a
proxyForFun _ = Proxy

instance Named Wrap where
name (Wrap named) = name (proxyForFun named)

但是,name 的类型非常受限:不再可能编写 name 检查其参数的实例,因此如果这是您需要的功能这种方法行不通。

关于haskell - 具有逆变位置变量的存在包装实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31863773/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com