简体   繁体   English

更高种类的功能?

[英]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 ? 必须有三个独立的函数, getXgetYgetZ 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有很多扩展,看起来他们可能有一个解决方案( RankNTypesExistentialQuantificationDataKinds等)。 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. 现在, XYZ的实际实现可以只使用默认签名并将提取减少到基础类型表示。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM