[英]Functions with higher kinds?
Suppose the following data types are defined: 假设定义了以下数据类型:
data X a = X {getX :: a}
data Y a = Y {getY :: a}
data Z a = Z {getZ :: a}
Must there be three separate functions, getX
, getY
, and getZ
? 必须有三个独立的函数,
getX
, getY
和getZ
? It seems to me that there could be a function defined something like this: 在我看来,可能有一个函数定义如下:
get :: forall (τ :: (* -> *)) (a :: *). τ a -> a
get (_ x) = x
Obviously this is not valid standard Haskell, but there are so many extensions to GHC that seem like they might have a solution ( RankNTypes
, ExistentialQuantification
, DataKinds
,etc.). 显然这不是有效的标准Haskell,但是GHC有很多扩展,看起来他们可能有一个解决方案(
RankNTypes
, ExistentialQuantification
, DataKinds
等)。 Besides the simple reason of avoiding a tiny amount of typing, there is the benefit of avoiding the namespace pollution that the record solution creates. 除了避免少量键入的简单原因之外,还有避免记录解决方案创建的命名空间污染的好处。 I suppose this is really just a more implicit solution than using a type class like this:
我想这实际上只是一个比使用这样的类型类更隐式的解决方案:
class Get f where
get :: f a -> a
However, it appears that defining a generic function would be more useful than a type class, because the fact that it is implicitly defined means it could be used in many more places, in the same way that ($)
or (.)
is used. 但是,似乎定义泛型函数比类型类更有用,因为它是隐式定义的事实意味着它可以在更多的地方使用,就像使用
($)
或(.)
。 So my question has three parts: is there a way to accomplish this, is it a good idea, and if not, what is a better way? 所以我的问题有三个部分:有没有办法实现这个目标,这是一个好主意,如果不是,那么更好的方法是什么?
How about this type? 这种类型怎么样?
newtype Pred a = Pred (a -> Bool)
Or this one? 还是这一个?
data Proxy a = Proxy
There's no way to get an a
out of a Pred a
. 有没有办法让一个
a
出来的Pred a
。 You can only put a
s in. Likewise, there's no way to get an a
out of a Proxy a
, because there aren't any a
s inside it. 你只能把
a
S IN。同样,有没有办法让一个a
走出了一条Proxy a
,因为没有任何a
里面秒。
So a function get :: forall f a. fa -> a
所以函数
get :: forall f a. fa -> a
get :: forall f a. fa -> a
can't exist in general. get :: forall f a. fa -> a
一般不存在。 You need to use a type class to distinguish between those types f
from which you can extract an a
and those from which you can't. 你需要使用一个类型的类的类型来区分
f
从中可以提取a
和那些你不能。
Well, that unconstrained generic type of get
certainly can't work. 好吧,那不受约束的泛型类型的
get
肯定不能工作。 This would also allow you to extract, say, a Void
value from Const () :: Const () Void
. 这也允许你从
Const () :: Const () Void
提取一个Void
值。
You can however obtain a suitably constrained version of this function quite simply with generics . 但是,您可以使用泛型非常简单地获得此函数的适当约束版本。 You still need a type class, but not need to define instances in the traditional sense.
您仍然需要一个类型类,但不需要定义传统意义上的实例。 It ultimately looks like this:
它最终看起来像这样:
{-# LANGUAGE TypeFamilies, DeriveGeneric, DeriveAnyClass #-}
import GHC.Generics
class Get τ where
get :: τ a -> a
data X a = X a deriving (Generic1, Get)
data Y a = Y a deriving (Generic1, Get)
data Z a = Z a deriving (Generic1, Get)
To actually get this to work, we only need two weird representation-type instances: 要实际让它工作,我们只需要两个奇怪的表示类型实例:
instance Get f => Get (M1 i t f) where get = get . unM1
instance Get Par1 where get = unPar1
Now the actual implementation for X
, Y
and Z
can just use a default signature and reduce the extraction to the underlying type-representation. 现在,
X
, Y
和Z
的实际实现可以只使用默认签名并将提取减少到基础类型表示。 To this end, define the class thus: 为此,定义类:
{-# LANGUAGE DefaultSignatures #-}
class Get τ where
get :: τ a -> a
default get :: (Generic1 τ, Get (Rep1 τ)) => τ a -> a
get = get . from1
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.