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

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

问题描述

当我阅读 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?我的想法是正确的还是我误解了语法?我知道我只是在猜测",但我希望在这里获得对这种能力的外行程序员"直觉,一些需要(或从中受益匪浅)的示例场景;)大多数情况下我可以想象(只是不是在什么确切的方式)这为那些小型嵌入式通用可递归配置语言"提供了更大的灵活性——Haskell 很高兴为……制定和编写 evals 的 ADT.关闭?

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天全站免登陆