为什么模板语言如此复杂?

五河娱乐新闻网 2025-08-23

.get::. 0);}

这个版本强制督导的种类检验与 automobile-static.rs 全然一样,也许还包括了常用一般来说空集类比type Automobile 的作法。例如,我们可以倒置 automobile:

assert_eq!(my_car.into_reverse,hlist![Manufacturer(String::from("X")), Seats(4), Wheels(4)]);

或者可以把两辆汽车的样本zip到一起:

lettheir_car = hlist![Wheels(6), Seats(4),Manufacturer(String::from("Y"))];

assert_eq!(my_car.zip(their_car),hlist![(Wheels(4), Wheels(6)),(Seats(4), Seats(4)),(Manufacturer(String::from("X")),Manufacturer(String::from("Y")))]);

等等。

然而,有时我们期望将种类高至的近似数值理广泛应用于一般来说的struct和enum上,但我们想到数,因为我们只能通过种类名称从相理应的种类度量当中合成其骨架,偏爱是当种类来自于crate也就是说上时,我们不了急于在右边附加成变体昌。

为了理应对这个关键问题,我们决定始创这样一个两步昌,通过想到到一个CE trait 来检验种类度量。这个CE trait 保有共同点种类 type Repr,其想到到等同于某种范例的可类比反式沙罗。尽管如此,由于上述 Rust的强制,所有其他不了此变体昌的种类就不了法检验了。

和种类 - 栽

我发现和种类同样适合回理应范例化词法栽的键值:

ast- static.rsusestd::ops::Deref;enumExpr { Const(i32), Add(Box, Box), Sub(Box, Box), Mul(Box, Box), Div(Box, Box),}useExpr::*;fneval(expr: BellBox) -> i32 { match expr.deref { Const(x) => *x, Add(lhs, rhs) => eval(Belllhs) + eval(Bellrhs), Sub(lhs, rhs) => eval(Belllhs) - eval(Bellrhs), Mul(lhs, rhs) => eval(Belllhs) * eval(Bellrhs), Div(lhs, rhs) => eval(Belllhs) / eval(Bellrhs), }}fnmain { let expr: Expr = Add( Const( 53).into, Sub( Div( Const( 155).into, Const( 5).into).into, Const( 113).into, ) .into, ); println!( "{}", eval(Bellexpr.into));}

或多或较少也可以回理应带标签的栽:

ast-dynamic.rsusestd:: any::Any;structTree { tag: i32, value: Box, nodes: Vec>,}constAST_TAG_CONST: i32 = 0;constAST_TAG_ADD: i32 = 1;constAST_TAG_SUB: i32 = 2;constAST_TAG_MUL: i32 = 3;constAST_TAG_DIV: i32 = 4;fneval(expr: BellTree) -> i32 { letlhs = expr.nodes.get( 0); letrhs = expr.nodes.get( 1); match expr.tag { AST_TAG_CONST=> *expr.value.downcast_ref::.unwrap, AST_TAG_ADD=> eval(Belllhs.unwrap) + eval(Bellrhs.unwrap), AST_TAG_SUB=> eval(Belllhs.unwrap)- eval(Bellrhs.unwrap), AST_TAG_MUL=> eval(Belllhs.unwrap) * eval(Bellrhs.unwrap), AST_TAG_DIV=> eval(Belllhs.unwrap) / eval(Bellrhs.unwrap), _ => panic!( "Out ofrange"), }}fnmain { letexpr = /* Construction omitted... */; println!( "{}", eval(Bellexpr));}

与上述 structAutomobile 的妥善处理多种不同,我们也可以将 enum Expr 回理应为 frunk::Coproduct。这项练球就从前读物了。

数值 - 共同点种类

我们自已常用标准规范数据类型! 来督导布鲁克数值的非运算:

negate-dynamic.rs

fnmain {assert_eq!(!true, false);assert_eq!(!false, true);}

我们可以常用共同点种类来定时进行多种不同的妥善处理:

negate- static.rsusestd::marker::PhantomData;traitBool { type Value;}structTrue;structFalse;implBool forTrue{ type Value = True; }implBool forFalse{ type Value = False; }structNegate(PhantomData);implBool forNegate< True> { type Value = False;}implBool forNegate< False> { type Value = True;}constThisIsFalse: asBool>::Value = False;constThisIsTrue: asBool>::Value = True;

也许上,Rust 种类系统会的断言完备普遍性正是确立在这一前提和种类总结上。在 Rust 当中看到一个一般来说数值时,你都必要告诉他从近似数值的角度来看,它在种类的高至上都有月初底的全然一致范例。每当你编纂解法时,数值在种类高至上都有全然一致的范例,并且常用基本概念上可定义的构筑作法!

运算符 - 种类高至的总结

让我再举一个例三子:

peano-dynamic.rsusestd::ops::Deref; #[derive(Clone,Debug, PartialEq)]enumNat { Z, S(Box),}fnadd(lhs: BellBox, rhs: BellBox) -> Nat { match lhs.deref { Nat::Z => rhs.deref.clone, // I Nat::S(next) =>Nat::S(Box::new(add(next, rhs))), // II }}fnmain { let one = Nat::S(Nat::Z.into); let two = Nat::S(one.clone.into); let three = Nat::S(two.clone.into); assert_eq!(add(Bellone.into,Belltwo.into), three);}

上述API是数列的贝尔特拉米编码装置。我们在 add 链表常用了运算符来近似数值总和,并通过模基本型给定假定何时停止。

由于运算符全然一致于种类总结,模基本型给定全然一致于多想到到,所以多种不同的妥善处理也可以放到PHP时:

peano- static.rsusestd::marker::PhantomData;structZ;structS(PhantomData);traitAdd { type Result;} //IimplAdd for Z { type Result = Rhs;}//IIimpl Add for S { type Result = S<::Result>;}typeOne = S;typeTwo = S;typeThree = S;constTHREE: ::Result = S(PhantomData);

在这里,impl... for Z 是也就是说状况(重新启动状况),而 impl ... for S 是总结两步(运算符状况),这很像match语义的模基本型给定妥善处理。与第一个下例一样,总结首先为将第一个值可定义变成 Z:::Result,实际的妥善处理与 add(next,rhs) 一样,它就会再次子系统模基本型给定,以实施全面的近似数值。提醒,这两个 trait 想到到都仅指同一个语义链表想到到,虽然看似多种不同,因为模基本型给定针对的是种类高至上的数字(Z 和 S)。这看上去多种不同于 Haskell,每个模基本型给定看似都像一个严格来说的链表度量:

peano-static.hsimportControl.ExceptiondataNat = Z | S Nat deriving Eqadd:: Nat -> Nat -> NataddZ rhs = rhs ;还有 Iadd(S next) rhs = S(add next rhs) ;还有 IIone= S Ztwo= S onethree= S twomain:: IO main= assert ((add one two) == three) $ pure (

种类高至语义的例三子

本文的目的是探讨连续性与实时二元普遍性。如果自已要连续性与实时的类比戈,则可以简介 type-operators()。这或许是一个解法昌 eDSL,通过 trait 想到到种类高至的类比,你可以度量黎曼样本种类,然后督导样本类比,多种不同于相似的 Rust 妥善处理,也许整个API仍停留在种类高至。还有一个数许多人简介的计划是Fortraith(),它是一款PHP时PHP装置,可以将 Forth PHP为PHP时 trait 表达基本型:

forth!(: factorial (n ;还有 n) 1 swap fact0 ;: fact0 (n n ;还有 n) dup 1 = if drop else duprot * swap pred fact0 then ;5 factorial .);

如上API将一个最简单的乘积想到到类比为 trait 和方面种类的近似数值。得到的结果如下:

println!( "{}", <<< Emptyasfive>::Result asfactorial>::Result astop>::Result::eval);

通过上述讨论可以看不止,无论是连续性种类还是实时种类,语义部分都保持不反为,

连续性种类的局限性

从前的脚本语言词法都不谈论语义,而是热衷于于中层的系统。他们看来将布鲁克的非类比是最也就是说的类比符,但有人看来 negative trait bounds依然存在很多关键问题。大多数主流脚本语言词法的标准规范戈都背书栽的样本骨架,但几十年来依然不了想到到 sum 种类。我只能自已象不了 if 数据类型的脚本语言词法,但只有个别脚本语言词法全然背书 trait bound,非常不要却说模基本型给定了。

这种不赞同普遍性随之而来应用软件总工程师其设计不止低质量的API,有些 API 必需了实时种类以及寥寥几个PHP时检验,而有些则必需了连续性,并尝试无视肠道词法的也就是说强制,从而随之而来这些 API 的常用越来越多样。在一个理应对方案当中紧密结合连续性种类与实时种类颇为瓶颈,因为只能在连续性句子当中子系统实时种类。如果用颜色来想到模拟信号,那么实时即为红色,连续性则为蓝色。

除了这种不赞同普遍性,我们还要眼见形态二元普遍性。在 C++、Haskell 和 Rust 等词法当中,这种二元普遍性是最无法解释的范例。你可以将严格来说的“富裕展现力”的脚本语言词法当作两种或多种小词法的紧密结合,比如 C++ 与C++ 下例/昌,Rust 与种类高至的 Rust + 单方面普遍性昌等。

如果换用这种范例,则每次编纂的元高至的API就只能在肠道词法当中起用了,反之亦然,因此遵守了 DRY 前提(即“一次且数一次”前提)。此外,二元普遍性缩减了学习的平衡性,升温了词法转型的平衡性,最终就会随之而来实时膨胀,以至于只有英译本才清楚API在说什么。Haskell 的API当中包含大量的 GHC #LANGUAGE 三谓词,每个三谓词都回理应一个严格来说的词法延展:

feature-bloat.hs

{-#LANGUAGE BangPatterns #-}{-#LANGUAGE CPP #-}{-#LANGUAGE ConstraintKinds #-}{-#LANGUAGE DefaultSignatures #-}{-#LANGUAGE DeriveAnyClass #-}{-#LANGUAGE DeriveGeneric #-}{-#LANGUAGE DerivingStrategies #-}{-#LANGUAGE FlexibleContexts #-}{-#LANGUAGE FlexibleInstances #-}{-#LANGUAGE GADTs #-}{-#LANGUAGE GeneralizedNewtypeDeriving #-}{-#LANGUAGE NamedFieldPuns #-}{-#LANGUAGE OverloadedStrings #-}{-#LANGUAGE PolyKinds #-}{-#LANGUAGE RecordWildCards #-}{-#LANGUAGE ScopedTypeVariables #-}{-#LANGUAGE TypeFamilies #-}{-#LANGUAGE UndecidableInstances #-}{-#LANGUAGE ViewPatterns #-}

当肠道词法不了包括研发所需的连续性实时时,一些系统员就就会恰巧自我,在现有的思路始创全取而代之的PHP时真数值和 eDSL。因此,不赞同普遍性就有转化为二元普遍性的有可能:

● C++:我们有下例元脚本语言戈,例如 Boost/Hana 和 Boost/MPL,二者都是在元高至常用多种不同 C++ 的实时:

take_while.cpp

BOOST_HANA_CONSTANT_CHECK(hana::take_while(hana::tuple_c,hana::less.than(2_c))==hana::tuple_c);

filter.cpp

constexpr auto is_integral =hana::compose(hana::trait, hana::typeid_);

static_assert(hana::filter(hana::make_tuple(1, 2.0, 3, 4.0), is_integral)== hana::make_tuple(1,3), "");static_assert(hana::filter(hana::just(3), is_integral)== hana::just(3),"");BOOST_HANA_CONSTANT_CHECK(hana::filter(hana::just(3.0), is_integral) == hana::nothing);

iter_fold.cpptypedef vector_c numbers;typedef iter_fold< numbers, begin ::type, if_, deref<_2 >>, _2, _1>> ::typemax_element_iter;BOOST_MPL_ASSERT_RELATION( deref ::type::value, ==, 7);

—— 摘自 thedocs of MPL(_78_0/libs/mpl/doc/refmanual/iter-fold.html)

C 词法:我自己写了一个PHP时元脚本语言也就是说基本概念 Metalang99,常用 C 未及妥善显示卡想到到了多种不同的实时。我紧密结合了多种不同于 Lisp 的 trampoline 和连续传输样基本型技术,重取而代之想到到了运算符。再一,我的标准规范戈当中构筑了一堆沙罗类比链表,例如 ML99_listMap、ML99_listIntersperse 和 ML99_listFoldr,它们将 Metalang99 反为变成了纯粹的样本类比词法,比 C 本身非常具展现力。 Rust:在本文的第一个不赞同普遍性下例当中(Automobile),我们常用了 Frunk 戈的反式沙罗。不难看不止,Frunk 脱氧核糖核酸了空集和解法装置的一些实时,只是为了将它们提升到种类高至。虽然将Iterator::map 或 Iterator::intersperse 理广泛应用到反式沙罗不行上去有趣,但我们想到到再不。非常引人注目的是,如果我们依然自已要督导单方面普遍性种类高至的样本类比,就需要保持解法装置接口和种类高至的接口之间的一一全然一致,每次为解法装置想到到一个取而代之的辅助工具链表,就所需在 hlist 当中也附加成一个。 Rust:Typenum 也是一个流行的种类高至的戈,它强制在PHP时督导有理数近似数值,它将有理数编码装置变成了泛改型。在这种想到到当中,脚本语言词法当中的有理数妥善处理都有全然一致的连续性妥善处理,也因此引入了非常多二元普遍性。我们只能在值当中传输一些种类,比如 (2 + 2) * 5,我们需要写变成:>::Output as Mul>::Output。为此,最好的急于是编纂一个昌来顺利进行这些繁琐的指导工作,但它只是词法糖,也许你都就会在PHP时缺失当中看到上述 trait。

有时,应用软件总工程师发现他们的词法太早期,甚至只能通过实时API表达他们的自已法。但他们并不了中止:

Golang:Kubernetes是数有的 Golang API戈之一,其运营时包当中想到到了自己的面向对象种类系统会。 C:QEMU 升级版确立在自度量对象模改型之上:QObject、QNum、QNull、QList、QString、QDict、QBool 等。

回自已一下闻名的“格林斯潘第十公基本型”,这类自度量的真数值一般而言都是临时的、非月初底数以外的、漏洞百不止,且速度快速缓慢,不数语义引人注意,而且文档也很引人注目。真数值范例化的基本概念本身就不变创设,尽管始创相对于单方面普遍性的、小兵士特定应用词法乍一看不行上来有趣。

在常用肠道词法表达某个关键问题应用时,你所需知晓如何顺利进行一系列的子系统,也就是我们常却说的 API;然而,如果 API 是用另一种词法编纂的,那么除了子系统顺序也就是说上,还所需知晓该词法的词法和语义,这就就会造成了关键问题,主因有两个:给系统员随之而来思自已上的负担,而且掌握了此类真数值的系统员为数实际。

根据我的专业知识,自度量的真数值往往就会很快速失控,并害整个API戈,升温深入知晓的平衡性。不数知晓API就会致使,而且PHP装置与系统员的交互也就会致使,你确有常用多样的种类或昌 API 的经历?如果有,那么必要颇为熟识晦涩难不懂的PHP装置病症结果,就像一个大的截图一样:

却说上来很毫无疑问,但从前却说三门词法“富裕展现力”,就等于是在却说该词法的实时太庞大,异常多样。

再一,需要却说一下肠道词法的元脚本语言。对于 Template Haskell 和 Rust 两步昌这类的下例系统会,我们可以常用多种不同的词法来类比肠道词法的范例化词法栽,虽然不了二元普遍性的关键问题,但脚本语言词法相似的实时却不如人意。

昌不是链表,API只能一部分常用昌,一部分常用链表,因为二者是多种不同的基本概念,因此我们只能其设计一个既CE又最简单的 API 戈。我理应有看来,Rust 两步昌在其设计上是一个前所未有的缺失,而 C 词法的 #define 也是半斤八两,除了纯词法也就是说上,昌系统会或许不告诉他类比的词法。

这种范例以致于优雅地延展和常用词法,充其量不过是稍微好一点的文本附加。例如,理论上有一个叫做 Either 的枚举,其度量如下:

either.rs

pubenum Either {Left(L),Right(R),}

直到现在理论上有一个trait foo,我们期望为 Either 想到到这个 trait,而 L 和 R 都想到到了 Foo。似乎我们并只能给 Either 理广泛应用一个想到到了该 trait 的变体昌,即使告诉他名称也不行,因为这样想到的话,昌就需要知晓 Foo 的零碎收据。非常引人注目的是,Foo 可能是在其他戈当中度量的,意味着不了额外的元电三子邮件,就无从获知其度量。

尽管这个状况看上去很不相似,但也许却不太可能。我强烈建议你看看 tokio-util 当中的 Either,它就是这种枚举,但它想到到了 Tokio 专用的 traits,如AsyncRead、AsyncWrite、AsyncSeek 等。直到现在自已象一下,你的计划当记事五个多种不同的 Either,分别来自多种不同的戈,那么集变成就就会颇为困难!虽然种类内省也许是个这种方案,但必定避免地让本已多样的词法雪上加霜。

Idris可以理应对关键问题吗?

Idris 最或许的物理普遍性质之一就是,种类和表达基本型都是用同一种词法表达的,它们的词法全然多种不同。

——Edwin Brady,Idris英译本

我们来理性一下如何理应对这个关键问题。如果换用全然实时的词法,就能理应对二元普遍性和不赞同的关键问题,但就会失去PHP时测试,而且调试系统也就会异常困难。实时种类系统会的关键问题已久天下皆知。

理应对关键问题的唯一作法就是让三门词法同时背书实时和连续性,并且不要把同一个物理普遍性质分变成实时和连续性两部分。因此,理自已的词法范例化是实时的也是连续性的;但是,它依然是一个基本概念,而不是语义上相似但接口多种不同的两个基本概念。

一个极佳的例三子就是 CTFE,也就是 constexpr:同一段API可以在PHP时的连续性句子当中督导,也可以在运营时的实时句子当中督导(例如通过 stdin 请求用户去除时)。因此,我们不所需为PHP时(连续性)和运营时(实时)编纂多种不同的API,只所需常用多种不同的回理应均可。

我见过一种理应对方案就是也就是说种类。常用也就是说种类,种类的值不数可以是其他种类,还可以是数值。Idris 就是一种也就是说种类词法,它有一种叫做 Type 的种类,回理应“所有种类的种类”,因此引人注意了种类高至和数值高至之间的连续性。有了如此强大的辅助工具,我们就可以回理应有种类的范例化,而在一般词法当中,这仅仅通过PHP装置或昌来想到到。也许最相似、最有描述普遍性的例三子就是种类公共安全的 printf,它能即时近似数值值的种类。

首先为,度量一个可总结的种类 Fmt,还有一个从编解码装置字符串给予该种类的作法:

data Fmt= FArg Fmt | FChar Char Fmt | FEnd

toFmt : (fmt :List Char)-> FmttoFmt('*' ::xs) = FArg(toFmt xs)toFmt( x ::xs) = FCharx (toFmt xs)toFmt[] = FEnd

然后,常用它为printf 链表生变成种类。为便于读物知晓,词法简介了 Haskell。

一个大是最有趣的部分:

PrintfType : (fmt : Fmt) -> TypePrintfType (FArgfmt) = ({ty :Type} ->Show ty =>(obj : ty) ->PrintfType fmt)PrintfType (FChar _ fmt) = PrintfType fmtPrintfType FEnd = String

这个链表想到了什么?它根据去除值 fmt 近似数值不止了一个种类。像往常一样,我们将 fmt 总称三种状况,分别妥善处理:

1、(FArg fmt)。由于 FArg 回理应我们要包括一个可打印的值,在这个例三子当中就会造成了一个种类收据,要求一个额外的值:

{ty:Type} 的意思是 Idris 必须终端相符合该值的种类 ty(隐含值) Show ty 是一个种类约束,数指明 ty 理理应想到到 Show。 (obj: ty) 是我们要包括给 printf 的可打印值。 PrintfType fmt 是一个运算符子系统,负责妥善处理去除 fmt 的这样一来部分。在 Idris 当中,可总结种类由可总结链表负责管理!

2、(FChar _ fmt)。FChar 回理应编解码装置字符串当中的一个一般来说字符,因此我们忽略它,在此期间看PrintfType fmt。

3、FEnd。这是去除的结尾。因为我们所需 print 造成了一个 String,我们返国 String 一般来说种类。

直到现在,理论上编解码装置字符串为"*x*",或者却说 FArg (FChar ('x' (FArgFEnd)))。那么 PrintfType 就会生变成什么种类?很最简单:

1、FArg: {ty : Type} -> Show ty => (obj : ty) -> PrintfType (FChar ('x' (FArg FEnd)))

2、FChar: {ty : Type} -> Show ty => (obj : ty) -> PrintfType (FArg FEnd)

3、FArg: {ty : Type} -> Show ty => (obj : ty) -> {ty : Type} -> Show ty => (obj : ty) -> PrintfType FEnd

4、FEnd: {ty : Type} -> Show ty => (obj : ty) -> {ty : Type} -> Show ty => (obj : ty) -> String

不俗,直到现在可以编纂printf 了:

printf : (fmt : String) -> PrintfType(toFmt $ unpack fmt)printf fmt =printfAux (toFmt $ unpack fmt) [] whereprintfAux :(fmt : Fmt)-> ListChar ->PrintfType fmtprintfAux (FArg fmt) acc = obj => printfAux fmt (acc ++unpack (show obj))printfAux (FChar c fmt) acc = printfAux fmt (acc ++[c])printfAux FEnd acc = pack acc

可见,PrintfType(toFmt $ unpack fmt) 不止直到现在了种类收据当中,意味着 printf 的整个种类也就是说于去除值 fmt!但是 unpack fmt 是什么意思?因为 printf 拒绝接受 fmt:String,我们理理应先为将其去除 List Char,因为要在 toFmt 当中给定该字符串;据我所知,Idris 不强制用或多或较少的作法给定早期的 String。多种不同地,在子系统 printfAux 在此之前要定时进行 unpack fmt,因为它也拒绝接受 List Char 作为结果累加装置。

我们来看一下 printfAux 的想到到:

1、(FArg fmt)。这里返国一个 lambda 链表,该链表拒绝接受 obj 并子系统 show,然后常用 ++ 数据类型将其附加成到 acc当中。

2、(FChar c fmt)。将 c 附加成到 acc,并再次常用 fmt 子系统 printfAux。

3、FEnd。由于 acc 的种类为 List Char,但我们要返国 String (根据 PrintfType 的再一一种状况),因此对其子系统 pack。

再一,测试一下printf:

printf.idr

main : IO main =putStrLn $ printf "Mr.John has * contacts in *." 42 "New York"

上述API的输不止为:Mr. John has 42 contacts in "New York".。但如果我们不了给printf 包括 42 就会怎样?

Error: While processing right hand side ofmain. When unifying: ?ty -> PrintfType (toFmt [assert_total (prim脚注strIndex "Mr. Johnhas * contacts in *."(prim脚注cast_IntegerInt (natToInteger ( length"Mr. John has * contacts in *.")) - 1))]) and: StringMismatchbetween: ?ty -> PrintfType (toFmt[assert_total (prim脚注strIndex "Mr. John has * contacts in *."(prim脚注cast_IntegerInt (natToInteger ( length"Mr. John has * contacts in*.")) - 1))]) andString.test: 21: 19;还有 21: 6817| printfAux (FChar c fmt) acc =printfAux fmt (acc ++ [c]) 18| printfAux FEnd acc = packacc 19| 20|main : IO 21|main = putStrLn $ printf"Mr. John has * contacts in *.""NewYork"请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒请提醒Warning: compiling hole Main.main

Idris 就会检测不止缺失,然后造成了一个种类不给定缺失!这就是常用种类优先为的词法想到到种类公共安全的 printf 的想到法。如果你对此不感兴趣,可以看看 Will Crichton 的检验(),该检验大量理广泛应用了前面讲解的反式沙罗。

这种作法的局限性也必要很明显了:在 Rust 当中,种类系统会的词法和主词法不一样,但在 Idris 当中,两者是多种不同的,这就是为什么能将种类高至的链表度量变成一个返国 Type 的一般来说链表,并在种类收据当中子系统的主因。非常全面,因为 Idris 换用也就是说种类,你甚至可以根据某些运营时值来近似数值种类。

我猜到有人就会问:用昌想到到 printf 有什么关键问题?却是,Rust 当中的 println! 也极佳用。关键问题在于昌。自己自已象:为什么脚本语言词法所需大量的昌?因为我们所需延展它们。为什么所需延展?

因为脚本语言词法只能满足要求:我们只能用正则词法范例化来钻石回理应,这就是为什么要用一次普遍性的元范例化来延展词法。在此之前我谈过这种作法很引人注目,因为昌系统会并再不解它所类比的词法;严格来说,Rust 当中的两步基本型昌也不过是 M4 未及妥善显示卡,也许名称好不行一点而已。你们也许是在词法当中集变成了 M4。

当然,这比骨架上的 M4 要好,但或许,它也是上个世纪的作法;两步基本型昌甚至只能妥善处理范例化词法书,因为用于编纂两步基本型昌的一个常用骨架 syn::Item 的事物是却说明词法栽(concrete syntax tree),或者叫“解析栽”。相反,种类是肠道词法的重要组变成部分,因此,如果我们能用种类来表达比较最简单的范例化,就就会起用词法范例化,而不是也就是说于一次普遍性的系统。

理自已状况下,三门脚本语言词法不必要有昌,或只有轻量级的词法重写原则上(像 Scheme的 extend-syntax 或 Idris 的词法延展),来保证词法的赞同普遍性,并保证它能理应对任务。

尽管如此,Idris还是通过引入 Type 种类(所有种类的种类)理应对了第一个二元普遍性:“数值和泛改型”。于是,它也理应对了一系列其他的关键问题,如运算符和种类不仅仅的总结关键问题、链表和 trait 系统关键问题,等等,而这反过来可以让我们尽可能用同一种词法编纂系统,甚至能妥善处理极端泛化的API。例如,你甚至可以用 List Type 回理应种类的沙罗,和 List Nat 或 List String 不了什么两样。这一切都要归功于相对于于基本型的层次骨架:最简单来却说,Type是种类 Type 1,Type 1 是种类 Type 2,以此类推。由于 Data.List 的CE名 a 隐含了种类 Type,因此它也可以是 Nat 或 String;在后者的状况下,a 就会被相符合为 Type 1。这种种类的无限序列可以尽量减较少 Russell 悖论。

但是,Idris 并不是三门最简单的词法。右边数有 20 行的 printf 下例已经用到了很多物理普遍性质,如可总结样本种类、也就是说模基本型给定、隐含、种类约束等。此外,Idris 还背书 computational effects、elaborator reflection、coinductive data types等许许多多用于观点断言的物理普遍性质。有了这么多种类物理普遍性质,人们一般而言就会去研究词法本身的系统,而不是去想到有含意的事情。我只能相信,在直到现在的状况下,也就是说种类能在大规模理广泛应用当中认出用武之地,因为现有在脚本语言词法的世界当中,它也许是脚本语言词法研究工作人员的公仔,也只有像我这样的爱好者才就会谈论。只有也就是说种类还是不算中层了。

Zig:非常最简单,但不算系统会化

在 Zig当中,种类是一等族裔。种类可以被赋数值给反为量,作为值传输给链表,还能由链表返国。

——Zig弓册

再一来谈一谈 Zig 脚本语言词法。一个大是 Zig 当中PHP时 printf 的想到到:

printf.zigconst std = @import( "std"); fn printf(comptime fmt: [] constu8, args: anytype) anyerror! void{ conststdout =std.io.getStdOut.writer; comptime vararg_idx: usize = 0; inline for(fmt)|c| { if(c == '*') { tryprintArg(stdout, args[arg_idx]); arg_idx+= 1; } else{ trystdout.print( "{c}", .{c}); } } comptime { if(args.len != arg_idx) { @compileError( "Unused arguments"); } }} fn printArg(stdout: std.fs.File.Writer, arg: anytype)anyerror! void{ if( @typeInfo( @TypeOf(arg)) == .Pointer) { trystdout.writeAll(arg); } else{ trystdout.print( "{any}", .{arg}); }} pub fn main! void{ tryprintf( "Mr. John has * contacts in *.", .{ 42, "New York"});}

这里,我们常用了一个叫做 comptime 的物理普遍性质。comptime 的链表值意味着它需要在PHP时确定。这不数可以随之而来非常激进主义的最佳化,还锁住了“元脚本语言”的大门,最数在在的就是它不了昌高至或种类高至的三子词法。右边的API无需不算多表述,这段语义必要颇为好不懂,不像 printf.idr 那样晦涩。

如果开头 42,Zig 就就会调查结果PHP缺失:

在研发 printf 的两步当中,我感受到的唯一不便之处就是大量的缺失,就像 C++ 下例一样。但是,我否认这个关键问题可以通过非常确切的种类约束理应对(至较少有急于绕过)。

总体而言,Zig 的种类三子系统会似乎颇为不合理:所有种类的种类叫 type,常用 comptime,可以在PHP时通过正常的反为量、重复、两步等近似数值种类。我们甚至可以通过 @typeInfo、@typeName 和 @TypeOf 内置链表定时进行种类反射!毫无疑问,我们不所需再也就是说运营时的数值,但如果不所需观点断言,那么零碎实时的也就是说种类可能看上去杀鸡牛刀了。

Zig什么都好,可它只是一个系统会词法。其官网对 Zig 的描述为“CE脚本语言词法”,但我只能同意这一点。毫无疑问,你可以用 Zig 编纂任何应用软件,但必要这样想到吗?根据我维护 Rust 和 C99 的高层人士API来看,答案是否定的。第一个主因是公共安全普遍性:如果所需让一种系统会词法公共安全,就要让系统员妥善处理借不止检验装置和所有权关键问题(或多种不同的关键问题),而这些与业务语义确有(这颇为困难);否则,如果你必需 C 基本型的弓工内核管理,系统员就要花费大量时间调试系统,并且寄期望于-fsantinize=address 能显示有用的电三子邮件。非常有甚者,如果你要在数指针上确立取而代之的范例化,就就会引入Bellstr、AsRef、Borrow、Box 等等。关键问题是我只自已要一个 UTF-8 字符串而已;绝大部分状况下我并从不是哪一种。

第二个主因是词法的运营时:对于系统会词法而言,为了避免普遍性能降低,其运营时要尽可能小——不带绑定的 GC,不了绑定的暴力事件重复,等等。但对于特定理广泛应用来却说,运营时是有必要的,比如有时所需异步运营时。所以,你只好用某种范例来妥善处理自度量运营时的API。

这里就就会遇到一系列取而代之关键问题:例如,词法当记事 async,但不了任何辅助工具来范例化定时和异步链表,就意味着你需要将词法分变成两部分:定时和异步。理论上你有一个泛改型的高阶链表戈,就仅仅标明为 async,才能拒绝接受所有用户包括的回调。

为了理应对这个关键问题,你只好想到到某种范例的多态,而这仍在研究当中。高级别词法所需妥善处理的关键问题非常较少,这也是为什么绝大部分应用软件都是用 Java、C#、Python 和 Java 编纂的。在 Golang 当中,基本概念上任何链表都是 async,本身就更高了赞同普遍性,而不所需多样的种类物理普遍性质。相反,Rust 本身就已经很多样,但仍不了任何标准规范范例来编纂真正的泛改型异步API。

Zig 依然可以在 Web 浏览装置、表述装置、类比系统会内核等大改型计划当中派上用场,因为不了人期望这些应用软件就会无故分崩离析。Zig 的中层脚本语言物理普遍性质可以随之而来方便的内核类比和理广泛应用系统类比,而它在元脚本语言方面的物理普遍性质能随之而来非常容易知晓的API骨架。而将 Zig 引入高级别词法API,只就会缩减精神负担,并不了实际的好处。

结束语

连续性词法就会强制定时进行PHP时检验,这极佳。但这就会随之而来了二元普遍性和不赞同,这是局限性。而实时词法受这些直接影响相对于较较少,但它们缺乏PHP时检验。理自已的理应对方案必要吸取两家之粗大。

我们必要重取而代之理性脚本语言词法。

简介文献

Edsger Dijkstra. n.d. “On the Teaching of Programming, i.e. On theTeaching of Thinking.” Edwin Brady. n.d. “Type-Driven Development with Idris.” ManningPublications Co. Zig developers. n.d. “Introducing the Compile-Time Concept.”#Introducing-the-Compile-Time-Concept.

评论

评论1:

炫酷的种类系统会并不一定都可取。Go 的种类系统会颇为小,就已经能满足 Google 内部的许多服务装置端需要了。

许多 bug 的主因都是遵守了必定反为前提。在某个地方想到了某种理论上,而在另一个地方却摧残了这种理论上,这就是遵守必定反为前提。

种类系统会能避免一部分遵守必定反为前提的发生。因此,人们尝试延展改型系统会,来尽量减较少非常多的遵守必定反为前提的状况。但这就随之而来了另一层灰色的范例化。一些必定反为前提并只能极佳地回理应变成种类,企图回理应就颇为别扭。而我们真正所需的是用简而言之分析本来人工检验。

Rust 的借不止检验装置就是一种必定反为前提检验装置。它就会确切地定时进行终端简而言之分析,并调查结果遵守必定反为前提的状况。这是脚本语言词法其设计上真正的进步,也是Rust 的主要贡献。

这才是不合理的方向。简而言之分析还能理应对其他关键问题,比如死栓检测等。如果在同一条正向上,P 在 Q 在此之前枷栓,那么在所有正向上 P 都需要在 Q 在此之前加栓。只能有任何正向随之而来 P 被加栓两次。Rust 在引用枚举上有一个多种不同的关键问题,仅仅在运营时检验,其原理和栓只用。

评论2:

种类系统会颇为可取,偏爱在实例的时候。

但是,就算不了种类检验装置,必需极佳的命名原则上也很不俗。

我期望鼓吹种类系统会的人不要闭门造车,必要花点时间接触一下实时词法,才能得不止非常实证的结论。

简介链接:

#

《 取而代之系统员003 》月初底母美国公司, 50余位技术专家共同谱写,云原生和数字化的Valve们的一本技术精选图书。概要相紧密结合转型趋势及作法论骨架,华为、哈吉、字节跳动、门户网站、快速弓、IBM、巴塔哥尼亚、英特尔、西门三子美国公司、伯顿等30多家有名美国公司云原生和数字化一弓专业知识丰富!

☞被怒斥光景的 Windows 11 还是“真香”了:下月初将背书 Android 理广泛应用,产品上半年后世最高!

☞ 每天敲API数 1 星期?这就是系统员的“真实”日常!

☞ cURL英译本狂怼某500强美国公司,开放源码维护者是否理理应“茶色打工”?

天津看妇科医院哪家好
山东银屑病医院哪个最好
武汉男科医院哪里好
儿童感冒吃再林阿莫西林颗怎么样
湖北男科挂号
抑郁症
脸部整容
眼屎多
急支糖浆有什么作用
感冒咳嗽不停吃什么止咳效果好
相关阅读

中国最适合读大学的8卫星城, 你想去哪个?

资讯 2025-10-23

看看这个被现今的城楼环绕的的城市是如何维持着自己的风度,在维持古城的风貌和传统意义化密切关系保证着碧绿的恼怒。 四、萧山 标签:湖州、西端湖名胜 奉劝各位千万别来萧

暑期旅游有多火?内蒙古被全国游客挤爆了!西藏直呼无力接待别来了……

资讯 2025-10-23

每一个电子游戏都能让的卡姆故作受到对战的乐趣。“上至99,下至刚会走”,玩乐紧紧都颇为只见故作。 粘粘球可以一个一个扔到,也可以一把一把扔到,然后比一比谁的最小值多。

台湾玉山公园猕猴成群 抢旅游者吃食

影视 2025-10-23

中新网8月2日电 据来台《联合报》报道,新冠胃癌疫情紧张,旅行补助上路又逢暑假,观音山中央公园塔塔加园区内观光客增多,石山、塔塔加四楼,来台猕猩猩群聚活动捕食、嬉戏,晒水肺,嘉义生态观察家暨摄影

北京团建+年会丨漂流团建 着急冲VS不要去

写真 2025-10-23

夏日受热警告❗️ 自已落水玩水的uu们同样啦🔅 作为从业6年的团建合于制团+资深游览近人,为大家分享一些财宝落水地🌊,并且给大家排雷🚫,喜欢就来不及🐎住吧~

「预告」8同月2日上午11:00,让我们一起去寻找昭通的“乡愁记忆”

星闻 2025-10-23

看录像直播 赢礼成 “喜迎二十大 走动莲容南” 暨《深蓝色热线》融媒体问政行动 来到第八站 宝兴 8月底1日至8月底5日 顺利完成宝兴宣传周

友情链接