什么类型的问题有助于“更高级的多态性"?更好的解决? [英] What types of problems helps "higher-kinded polymorphism" solve better?

查看:16
本文介绍了什么类型的问题有助于“更高级的多态性"?更好的解决?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

当我通读 Haskell 的历史,我遇到了:

As I read through some sections in History of Haskell, I came across:

然而,更高种类的多态性具有独立的效用:声明数据类型参数化到更高种类是完全可能的,而且有时非常有用,例如:

However, higher-kinded polymorphism has independent utility: it is entirely possible, and occasionally very useful, to declare data types parameterised over higher kinds, such as:

data ListFunctor f a = Nil | Cons a (f a)

了解基本"ADT 我在这里有点困惑,我的猜测"是括号中的部分暗示了参数"/动态"一元数据构造函数 f?所以任何 * -> 类型的数据构造函数* 那个可以接受"的类型a?我的想法是正确的还是我误解了语法?我知道我只是在猜测",但我希望在这里获得对此功能的外行程序员"直觉,一些示例场景需要(或从中受益匪浅);)大多数情况下我可以想象(只是不是在什么确切的方式)这允许在那些小型嵌入式多功能可递归配置语言"-ADTs 中提供更大的灵活性,Haskell 很高兴为……制定和编写 evals ......关闭?

Knowing "basic" ADTs I was a bit puzzled here, my "guess" was that the part in parens suggests a "parametric"/"dynamic" unary data constructor f? So any data constructor of kind * -> * that "can accept" type a? Is my thinking correct or am I misinterpreting the syntax? I know I'm "just guessing" but I'm hopeful to gain a "lay-programmer" intuition on this capability here, some sample scenario needing (or benefiting immensively from) this ;) mostly I can imagine (just not in what exact manner) this allowing more flexibility in those "small embedded versatile recursable config language"-ADTs that Haskell makes such a pleasure to formulate and write evals for.. close?

在 GHCi 中,:i ListFunctor 上面给出:

In GHCi, :i ListFunctor on the above gives:

type role ListFunctor representational nominal
data ListFunctor (f :: * -> *) a = Nil | Cons a (f a)

所以这似乎是从更清晰的 data 声明中推断"出来的.

So this seems to be what's "inferred" from the crisper data declaration.

推荐答案

是的,f 可以是任何一元类型的构造函数.

Yes, f can be any unary type constructor.

例如 ListFunctor [] IntListFunctor Maybe Char 都很好.

For instance ListFunctor [] Int or ListFunctor Maybe Char are well-kinded.

f 也可以是部分应用了 (n-1) 个参数的任何 n 元类型构造函数.

f can also be any n-ary type constructor with (n-1) arguments partially applied.

例如 ListFunctor ((->) Bool) IntListFunctor (Either ()) Char 都很好.

For instance ListFunctor ((->) Bool) Int or ListFunctor (Either ()) Char are well-kinded.

基本的分类系统非常简单.如果 F :: * ->* ->... ->*,然后 F 需要类型参数.如果 G :: (* -> *) ->*,然后 G 期望任何类型的 * ->* 包括如上所示的一元类型构造函数和部分应用程序.等等.

The basic kinding system is quite simple. If F :: * -> * -> ... -> *, then F expects type arguments. If G :: (* -> *) -> *, then G expects any thing of kind * -> * including unary type constructor and partial applications as the ones shown above. And so on.

高级类型很好解决的一个问题是配置选项.假设我们有一个记录

A problem which is nicely solved by higher kinds is configuration options. Assume we have a record

data Opt = Opt 
   { opt1 :: Bool
   , opt2 :: String
   -- many other fields here
   }

现在,可以在文件中找到配置设置和/或通过命令行和/或环境变量传递.在解析所有这些设置源的过程中,我们需要应对并非所有源都定义所有选项的事实.因此,我们需要一个更宽松的类型来表示配置设置的子集:

Now, configuration settings can be found in a file and/or passed through the command line and/or in environment variables. During the parsing of all these settings sources, we need to cope with the fact that not all sources define all options. Hence, we need a more lax type to represent subsets of configuration settings:

data TempOpt = TempOpt 
   { tempOpt1 :: Maybe Bool
   , tempOpt2 :: Maybe String
   -- many other fields here
   }

-- merge all options in one single configuration, or fail
finalize :: [TempOpt] -> Maybe Opt
...

这太可怕了,因为它重复了所有选项!我们很想删除 Opt 类型,而只使用较弱的 TempOpt 类型,以减少混乱.但是,通过这样做,即使在初始配置处理部分之后,每次我们需要访问程序中选项的值时,我们也需要使用一些部分访问器,如 fromJust.

This is horrible, since it duplicates all the options! We would be tempted to remove the Opt type, and only use the weaker TempOpt, to reduce clutter. However, by doing this we will need to use some partial accessor like fromJust every time we need to access the value of an option in our program, even after the initial configuration handling part.

我们可以改用更高的种类:

We can instead resort to higher kinds:

data FOpt f = FOpt 
   { opt1 :: f Bool
   , opt2 :: f String
   -- many other fields here
   }
type Opt = FOpt Identity
type TempOpt = FOpt Maybe

-- as before: merge all options in one single configuration, or fail
finalize :: [TempOpt] -> Maybe Opt
...

不再重复.在我们finalize 配置设置之后,我们得到了设置始终存在的静态保证.我们现在可以使用 total 访问器 runIdentity 来获取它们,而不是危险的 fromJust.

No more duplication. After we finalize the configuration settings, we get the static guarantee that settings are always present. We can now use the total accessor runIdentity to get them, instead of the dangerous fromJust.

这篇关于什么类型的问题有助于“更高级的多态性"?更好的解决?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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