更广泛的新型派生 [英] Even more generalized newtype deriving

查看:125
本文介绍了更广泛的新型派生的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Newtypes通常用于在某些类上下文中改变某些类型的行为。例如,使用 Data.Monoid.All 包装器来更改 Bool 在用作 Monoid



我目前正在编写这样一种适用于大范围不同类型的新类型包装器。包装应该改变一个特定类实例的行为。它可能看起来像这样:

  newtype包装器a =包装器a 

实例Special a => Special(Wrapper a)其中
- ...

但是,添加此包装将经常会改变包装类型的可用性。例如,如果我以前能够使用函数 mconcat :: Monoid a => [a] - > ,我现在无法将它用于包装值列表。



我当然可以使用 -XGeneralizedNewtypeDeriving newtype包装器a =包装派生(Monoid)。然而,这只能解决 Monoid 的问题,并且没有其他类,而我将处理一个充满不同类的开放世界,而孤立的孤立泛化新类型派生不是真的一个实用的选择。理想情况下,我想编写派生隐藏(Special)(派生每个类,除 Special )外,但这不是当然有效的Haskell。



有没有这样做的方法,或者我只是搞砸了,需要添加GHC功能请求?

解决方案

请看 GeneralizedNewtypeDeriving 是不安全的。在这种情况下,这是一种不安全的做法。

  { - #LANGUAGE GADTs,ConstraintKinds# - } 
import Data.Monoid
import Unsafe.Coerce

data Dict c where
Dict :: c =>字典c

newtype包装器a =包装器a

addDictWrapper :: Dict(f a) - > Dict(f(Wrapper a))
addDictWrapper = unsafeCoerce

你随时可以使用它你需要typeclass实例

  intWrapperNum :: Dict(Num(Wrapper Int))
intWrapperNum = addDictWrapper Dict

two :: Wrapper Int
two = case intWrapperNum of
Dict - > 1 + 1

这个传递显式字典的系统非常普遍,并且具有相当不错的(尽管实验)库支持它称为 Data.Constraint


Newtypes are often used to change the behavior of certain types when used in certain class contexts. For example, one would use the Data.Monoid.All wrapper to change the behavior of Bool when used as a Monoid.

I'm currently writing such a newtype wrapper that would apply to a large range of different types. The wrapper is supposed to change the behavior of one specific class instance. It might look like this:

newtype Wrapper a = Wrapper a

instance Special a => Special (Wrapper a) where
  -- ...

However, adding this wrapper will often change the usability of the wrapped type. For example, if I previously was able to use the function mconcat :: Monoid a => [a] -> a, I am not able to now use it for a list of wrapped values.

I can of course use -XGeneralizedNewtypeDeriving and newtype Wrapper a = Wrapper a deriving (Monoid). However, this only solves the problem for Monoid and no other class, while I will be dealing with an open world full of different classes, and standalone orphan generalized newtype deriving is not really a practical option. Ideally, I'd like to write deriving hiding (Special) (deriving every class except Special), but that's not valid Haskell, of course.

Is there some way of doing this or am I just screwed and need to add a GHC feature request?

解决方案

Look, GeneralizedNewtypeDeriving is unsafe. In that vein, here is an unsafe way of doing it

{-# LANGUAGE GADTs, ConstraintKinds #-}
import Data.Monoid
import Unsafe.Coerce

data Dict c where
  Dict :: c => Dict c

newtype Wrapper a = Wrapper a

addDictWrapper :: Dict (f a) -> Dict (f (Wrapper a))
addDictWrapper = unsafeCoerce

you can then use it anytime you need the typeclass instance

intWrapperNum :: Dict (Num (Wrapper Int))
intWrapperNum = addDictWrapper Dict

two :: Wrapper Int
two = case intWrapperNum of
           Dict -> 1 + 1

this system of passing around explicit dictionaries is highly general, and has a pretty good (although experimental) library to support it called Data.Constraint

这篇关于更广泛的新型派生的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆