Julia: mini julep: if x then y

创建于 2016-05-16  ·  53评论  ·  资料来源: JuliaLang/julia

在各种讨论中,建议允许使用如下语法:

if x then y

作为一个简短的“if”语句和通用的替代:

x && y

利用短路&&运算符有条件地执行y的语法(其中y通常包含其他副作用,不一定返回Bool )。

这个if-then结构的主要优点是:更易读的代码,更少依赖滥用&& ,并且正式包含不需要end的“if”语句形式关键词。

前几天我突然想到,这种语法也可以提供一种方便的方法来实现#550,它看起来像:

A = [if x % 2 == 0 then f(x) for x in 1:10]

依靠if-then不需要end关键字这一事实,即使我们使用 python 样式的守卫,我们也可能需要某种形式的关键字:

A = [f(x) for x in range(10) if x % 2 == 0]

需要明确的是,Julia 守卫语法本质上是从以下内容进行重写:

A = [if x % 2 == 0 then f(x) for x in 1:10]

A = [Filter(x->x % 2 == 0, f(x) for x in 1:10)]

同样作为澄清说明,这将允许在 _generator_ 级别而不是仅在 _comprehension_ 级别(这与 python 允许的内容相匹配)的保护语法。

julep

最有用的评论

也许我是少数,因为其他语言也采用了这种方法,但我总是发现条件之前的动作真的很奇怪,例如println("positive") if x > 0 。 我想它比if x > 0 println("positive") end更简洁,但至少对我来说它是以可读性为代价的。

我把它想象成一个对话:

朱莉娅:“我要打印一个字符串……”
哈罗德:“太棒了!”
朱莉娅:“……但前提是满足某些条件。”
哈罗德:“哦。:(”

相对

Julia:“如果满足某些条件,我会打印一个字符串。”
哈罗德:“好吧,很酷。”

所有53条评论

Perl/Ruby 风格的 if/for 修饰符语法似乎会更好地与此混合。 换句话说:

println("positive") if x > 0         # conditional execution
x^2 for x=1:100                      # generator
[ x^2 for x=1:100 ]                  # comprehension
x^2 if x % 3 == 0 for x = 1:100      # filtered generator
[ x^2 if x % 3 == 0 for x = 1:100 ]  # filtered comprehension

它还具有在其他语言中具有先例的好处,而没有end语法的if - then似乎没有。

只是关于问题管理的一个旁注:#6823 正是讨论了这个问题。 在某些时候它被关闭而没有评论,我跟进询问它为什么被关闭,因为显然没有达成共识来关闭它,但从未得到答复。 似乎不关闭 #6823 之类的问题会更有效,否则这些讨论将只是循环往复,并且将再次重复原始问题中的所有要点。 在某些时候更改#6823 的标题可能是有意义的,然后在此处添加。

是的,好点。 事实上,#6823 似乎是在讨论中,可能不应该被关闭。

也许我是少数,因为其他语言也采用了这种方法,但我总是发现条件之前的动作真的很奇怪,例如println("positive") if x > 0 。 我想它比if x > 0 println("positive") end更简洁,但至少对我来说它是以可读性为代价的。

我把它想象成一个对话:

朱莉娅:“我要打印一个字符串……”
哈罗德:“太棒了!”
朱莉娅:“……但前提是满足某些条件。”
哈罗德:“哦。:(”

相对

Julia:“如果满足某些条件,我会打印一个字符串。”
哈罗德:“好吧,很酷。”

@ararslan :我不反对,这是尽管 Ruby 和 Perl 中的现有技术,但此功能不在 Julia 中的原因之一。 但是,它确实与生成器和推导的for修饰符语法混合得更好,这就是我在这里提出它的原因。

@StefanKarpinski是的,同意,它确实与这些更吻合。 我仍然无可救药地依附于行动之前的条件。 :smile: (但正如我发现自己最近经常说的那样,我的意见并不重要;我只是一个人。)

我想如果你有类似的东西

if x % 3 == 0 then x^2 for x = 1:100

那么并不清楚您正在启动一个理解/生成器/thingamajig,因为它也读起来好像可以像这样分组

if x % 3 == 0 then (x^2 for x = 1:100)

即,如果某些条件则生成器。 我不介意

if x % 3 == 0 x^2 end for x = 1:100            # More obvious what's happening, IMO
filter(x -> x % 3 == 0, [x^2 for x = 1:100])   # Verbose, but... ¯\_(ツ)_/¯

我想如果条件是遵循生成器中的操作,我想我更喜欢与if不同的关键字,例如where 。 然后它读起来几乎就像一个 SQL 查询,例如

x^2 for x = 1:100 where x % 3 == 0

我认为where forif过滤x的值更清楚一点。

对我来说,让数据流向单一方向似乎更好,尽管在这种情况下从右到左而不是从左到右。

你能详细说明你的意思吗?

for 1:n “生成”值, if x % 3 == 0过滤它们, x^2转换它们——生成器已经从右到左流动,为了保持这种流动,过滤器需要进入中间。 如果if子句位于for子句的右侧,那么数据会从中间“流动”到最右边,然后到最左边,这很奇怪。 如果if子句在左侧,则数据从最右侧“流动”到最左侧到中间。 我知道 SQL 把where子句放在表名的右边,把表达式放在左边——因为这读起来更像英语——但我一直觉得这读起来很烦人,我认为读起来像英语不是在编程语言设计中应该采取的启发式方法。

我不喜欢if x then y的事情:

  1. 它引入了新的then关键字。
  2. if x y end if x then y更短; x && y甚至更短。
  3. then关键字在语言中广泛用于完全相反的语法:多行if语法需要end关键字(或 bash 中的fi ,呸)。

哦,是的,我明白你现在关于流量的意思了。 这就说得通了。 感谢您的解释!

能做会不会很奇怪

x^2 if x % 3 == 0 for x = 1:100

并且_不能_做

println("positive") if x > 0

?

所有的好点。

我真的很喜欢@StefanKarpinski在他的第一条评论中首次提出的语法。 我主要对条件生成器感兴趣,并以更通用的短格式 _if_-form 作为奖励。

关于生成器,我正在阅读if (或where - 我对此没有意见)作为范围的一部分......它正在创建一个迭代器x = 1:10 if/where x % 2 == 0 ,它然后与左侧的表达式组合以创建一个数组(或生成器)。

从某种意义上说, x = 1:10 where x % 2 == 0本身就是某种可迭代对象的生成器。 这可能是独立的语法,不是吗?

我觉得过滤在某种程度上是与条件if a then b语句不同的操作。 过滤作用于迭代范围。 当if a then b与生成器左侧的表达式结合时,我希望它在afalse的情况下发出nothing #$ 。 比较如果我添加括号,逻辑上会发生什么:

[(x^2 if i % 2 == 1) for i = 1:10] # [nothing, 4, nothing, 16, nothing, 36, nothing, 64, nothing, 100]
[x^2 (for i = 1:10 where i % 2 == 0)] # [4, 16, 36, 64, 100]

@ararslan为例,如果我们允许的话

println("positive") if x > 0

然后恕我直言,它遵循

x^2 if x % 3 == 0 for x = 1:100

应该可能发出nothing, nothing, 9, nothing, nothing, 36, ...

最后,如果我们要采用简写if条件,我的投票是声明之前的条件,原因在@ararslan的第一篇文章中概述 - 是阅读代码时最不意外的原则。 (请记住,如果他们说代码的阅读量多于编写量,那么if a then b的语法比a && b更好,即使后者更短)。 这也意味着生成器内的两种可能的if类型将是不同的 - 在最左边 - 与表达式 - 或在最右边 - 与范围。

至于 Ruby/Perl 的传统,我觉得最好尝试提出最好的解决方案,而不是被传统所束缚。 如果它有效并且感觉自然,人们会喜欢它。

此外,如果我们在范围中有if/where ,我们是否需要小心确保范围对于多维生成器保持笛卡尔坐标?

# Make a circular array (filled with distance to center)
r = 5
[sqrt(x^2 + y^2) for x = -5:5, y = -5:5 where x^2 + y^2 <= r^2]

这有点酷,有点可怕!

我觉得过滤在某种程度上是与条件 if a then b 语句不同的操作。

是的! 我正要发表同样的评论。 过滤作为一个整体对迭代器进行操作,而不是内部计算表达式的一部分。

我也和@andyferris的感觉一样,表达式和迭代之间的if似乎“转换”了表达式的值而不是迭代的形状,并且应该产生nogthing时不满足条件(但我可能被 python/haskell 理解宠坏了)。

显然,当不在生成器表达式的上下文中时, x if false将评估为nothing 。 支持[x^2 if x % 3 == 0 for x=1:100]而不是x if y本身是完全合理的。

就个人而言,如果只有一个语句,我宁愿能够省略end

if length(A) != length(B) throw(ArgumentError("..."))

如果没有end ,那么它可以假设只有一个表达式。 我猜这之前已经详细讨论过了?
我注意到我不希望在条件之后使用分号 - 在表达式之后......_也许_......虽然我不喜欢它。

我宁愿这样,也不愿为类似形式的 if 语句使用两种不同的语法;if x; ...; endif x then; ... _(编辑: if condition then action在我身上长大了。)_

支持 [x^2 if x % 3 == 0 for x=1:100] 但不支持 x if y 本身是完全合理的。

@StefanKarpinski我完全同意这一点。 然而...

如果 if 子句在左侧,则数据从最右侧“流动”到最左侧到中间。

我将x^2 if x % 2 == 0 for x in 1:10读为x^2 where x % 2 == 0 for each x in 1:10 ,因为它是理解性的,所以对我来说很有意义; 你对转型最感兴趣。
在 SQL 查询中,同样的观点是正确的,不是吗?

因此,我不认为将“生成器”作为阅读它的起点是完全正确的,_for a comprehesion_。 另一方面,一个 for 循环......这更有意义。

就个人而言,如果只有一个语句,我宁愿能够省略 end 。

我很久以前就提出了这个,但没有得到任何支持: https://github.com/JuliaLang/julia/issues/1657。 这实际上是一个相对无破坏性的更改,因为看到一些这样的编写代码会很奇怪而且很少见:

if cond body
end

您如何看待使用do块而不是then ? 即: if x do y end

只是一个小小的旁注:我看不出有任何方法可以在没有成熟的 julia 解析器的情况下在编辑器中正确处理if x y本身(即在生成器之外),因为您需要能够确定有多少令牌跟随if 。 我正在考虑 vim,但我想其他编辑器可能处于同样的情况。 y if x可能也是如此,但我不确定(完全披露:我也很不喜欢y if x本身;我原则上并不反对if x y但认为对于人类来说也可能有点难以解析,不仅是编辑)。

@diegozea我认为同样的问题。 我还是更喜欢if x y

@carlobaldassi您可以做一些事情来使人类更容易解析。

您可以强制该单语句 ifs 在条件和表达式之间没有换行符。
不过,我不确定我是否愿意被迫在长时间的表达中这样做。

或者,如果条件后有换行符,则可以强制表达式后有换行符; 因此,以下内容不会编译,但当然会给出明确的错误消息:

if length(A) != length(B)
    throw(ArgumentError("lengths must match")
if some_condition(A, B)
   N *= 2

但是,这将:

if length(A) != length(B) throw(ArgumentError("lengths must match")
if some_condition(A, B) N *= 2

这将:

if length(A) != length(B)
    throw(ArgumentError("lengths must match")

if some_condition(A, B)
   N *= 2

这也可以防止你犯这种错误:

if is_present(x)
    y = 2 * x[]

    return y * 2

我认为if x then y仍然胜过任何其他语法的最大论点是可读性if x y endif x yx && y更短在我的书中是无关紧要的(除了我们谈论的是微不足道的 1-5 个字符差异),因为这些都不是几乎和if x then y一样清晰。 它还避免了编辑器解析问题或可能破坏过去代码。 对于短 if 语句来说,这只是一个不错的、干净的、简短的语法。

但是,我确实认识到在生成器案例中使用if-then的潜在混淆; 鉴于此,我同意

x^2 if x % 3 == 0 for x = 1:100      # filtered generator
[ x^2 if x % 3 == 0 for x = 1:100 ]  # filtered comprehension

是最清楚的,认识到表达结构是

generated_value_expr  value_generator_expr  =>  generator_expression

[generator_filter_expr]  for_generator_expr  => value_generator_expr

generator_filter_expr直接应用于从for_generator_expr生成的值,然后将未过滤的值传递给generated_value_expr

我认为这里的区别很重要,因为它不是允许的相同逻辑

println("positive") if x > 0 

TL;DR:我们应该有x^2 if x % 3 == 0 for x = 1:100过滤生成器,但相同的语法逻辑不适用于println("hey") if x > 0 ,因此,我们仍然应该考虑if x then y短格式if 语法。 尽管显然这里的两个想法现在完全不相关。

@H-225 这对我来说似乎很奇怪并且最终不是朱利安,特别是在没有end的新行上采取行动。

对于编辑器来说,解析仍然是一场噩梦,因为编辑器(如 Vim)不在乎什么是条件或动作,什么不是条件或动作——事实上,如果没有 Julia 解析器,他们无法知道——而是他们关心诸如ifend之类的东西的位置。 我认为让 Vim 认识到在那种情况下不需要end是非常困难的。 我意识到让编辑更容易不是设计决策的好论据,我只是说。

绝对 :-1: 来自我的if x y 。 我更喜欢if x then y ,因为我的小大脑更容易解析。 :stuck_out_tongue_winking_eye:

是否有理由不简单地将三元问号运算符也用于 if 语句? 您已经可以通过这样做来模仿 if 语句

condition ? if_condition_true_eval_expr : nothing

为什么不这样做,如果你不包含冒号,那么它就是一个 if 语句,那么你就会有

condition ? if_condition_true_eval_expr

这样你就不必引入任何新的关键字,这行得通吗?

@esproff有趣的是,我打算提出相反的建议:将这个 julep 中的 if-then 想法扩展到单行 if-then-else 表达式

if cond then a else b

else 子句是可选的。 它甚至可能低于cond ? b : c 。 对我来说,这一切都是为了摆脱 C 风格的三元组,转向更易于阅读的代码。 (我之前肯定使用过condition ? a : nothing - 这似乎是一个 hack(因为它是, nothing出于某种模糊的原因很重要)并且其他人阅读时会感到困惑)。

但是,当然,为什么我们不能同时拥有所有这些想法呢?

@andyferris是的,这是另一种 Pythonic 方式。 我想这取决于你想变得多么简洁,数学家通常似乎很喜欢简洁,但老实说,只要我不必使用笨重的东西,我都会很高兴

if condition; eval_expr; end

但老实说,我会很高兴,只要我不必使用笨重的

if condition; eval_expr; end

的确!

对于它的价值,我喜欢 x && y 符号并且不认为它是一种滥用。

我个人更喜欢基于运算符的解决方案,如果第一条语句为假,则不返回false 。 尽管我喜欢将a ?: b作为三元运算符的两个参数版本,但我几乎可以处理任何事情。

?的想法在 #6823 中得到了相当广泛的讨论,可能值得重新阅读该讨论。

我从那次讨论中来到这里,但认为这是一个更好的发表评论的地方。 我认为if a then b和仅使用?而不使用:都会有些混乱,但只要它们提供相同的功能就不会抱怨。

我同意@EricForgy。 也许我现在只是习惯了它们,但对我来说,以这种方式使用&&||对 Julia 来说是惯用的,特别是对于错误检查(例如x || throw(y) )。 它们看起来一点也不模棱两可或难以理解。 另外,我真的不明白为什么如果x为 false 时x && y返回false x很重要,因为无论如何它可能不应该在函数末尾使用,它会影响函数的返回值。

C 风格的三元组非常普遍。 我认为不只是数学家重视这种语法。 我能想到的唯一一种具有三元组但不支持 C 风格的语言是 Python,而 FWIW 我鄙视 Python 三元组。 只要您使用空格并尊重行长, condition ? action1 : action2就既紧凑又可读。 对于更长的条件和动作,应该使用

if condition
    somelongaction1
else
    somelongaction2
end

无论如何为了可读性。

关于then ,本次讨论的重点,FWIW 我可能不会使用它,即使它已实现,因为再次, &&||对我来说是惯用的。 虽然我会在if x yx ? yx ? y : nothing的心跳中服用then x ? y : nothing

就个人而言,我更喜欢y if x 。 它可能看起来是错误的方式,但除了 Ruby 和 Perl 之外还有优先级:数学案例语法有这种方式

image

我不_喜欢_为此使用&&|| ,因为我从不记得x && y = z没有按照我期望的方式解析。 我认为它比y if x具有更高的认知负荷; 这也适用于if x y

IMO, x ? y _smells_ 就像一个语法错误,不管它是否真的有效。

x ?? y也许? x ?: y是一个 GNU C 扩展,意思是x ? x : y ,所以???:可能是&&||的低优先级版本

我的偏好顺序: y if x == x ?? y < if x then y < x && y < x ? y < if x y

FWIW。 我更喜欢用?&&||将代码简洁明了地分开,尽管cond ? expr语法可能比&&更清晰

我确实喜欢经常做goodcondition || return类型的流程,这对于 if 语句来说并不容易。 我不想失去它(或被欺负不使用它)

对于没有:的三元组,允许没有else条件的简洁if / elseif块可能会很好:

x==5 ? f1() :
x==6 ? f2()

并且可以想象将其扩展到 switch 类型的语句:

match x:
    5 ? f1() :
    6 ? f2()

就可读性而言,这取决于。 对于许多简短的条件/动作,它更具可读性(使用干净的间距!!)能够使用清晰的分隔符将条件/动作排列在连续的行上。

对于生成器,我更喜欢wherewhen而不是重新利用if ,因为它是过滤器,而不是条件:

x = [i^2 for i in 1:10 when i%2 == 0]

我认为这意味着x = [i^2 for i in filter(..., 1:10)]更清楚。

我会注意到,自从讨论这个问题后,我将不再反对if condition then action - 它是在我身上成长起来的。
朱莉娅确实倾向于更“罗嗦”的一面,有functionend等,所以我认为它很适合。不得不在周围加上括号也有点烦人如果您在condition && action语法之间来回切换表达式。

关于 Perl/Ruby 语法“action if condition”:我真的很喜欢这种语法,虽然我同意它在使用不当时会降低可读性,但我也相信它有时会_增加_可读性。

例如:

throw(DomainError()) if some_condition || some_other_condition && so_on

在阅读“throw domain error if”之后,您已经知道接下来将是对输入的健全性检查。 如果条件的详细信息对您不重要,您可以跳到下一行。

上一句是这种结构在自然语言中如何频繁出现的一个例子。 动作“跳到下一行”首先出现,不太重要的“如果你不感兴趣”出现在从句中。 同样,读者可能无需实际阅读到句子的结尾,就可以大致猜测“如果”一词后面会出现什么。

(如果我能想到的话,我也会给出一个自我参照的例句。)

作为一个 Perl 的老手,我很同情这种语法,但我认为这对于那些没有 Perl 背景的人来说会很难卖。 一个赞成的论点是它与理解中的过滤器语法相匹配。 反对的一个论点是,有一个评估顺序不是从左到右的构造是很奇怪的。 当然,推导也正是如此,所以🤷‍♂️

对我来说,一个相关的问题是:我们是在泛化分支还是过滤? 这是分支if语义(和语法)的概括,因此如果该语法已经指示过滤,则为此目的从理解/生成器中借用语法可能是不幸的。

(顺便说一句,我喜欢一些好的过滤语法,比如我们好的.语法。为了说明我上面的观点,也许map - filter可能看起来像f.(a) if g.(a)

f(x) for x in a # lazy map
f(x) for x in a if g(x) # lazy map - filter
x for x in a if g(x) # lazy filter where `f` is `identity`

f.(a) # map / broadcast
f.(a) if g.(a) # like a map/broadcast - filter operation
a if g.(a) # like the above where `f` is implicitly `identity`
[1,2,3] if [true, false, true] == [1, 3] # or something... here we simply make `if` an infix operator for filtering

很抱歉跑题了,我不确定上面是不是一个好主意,但只是指出理解过滤if语法可能有另一种潜在用法,它具有过滤语义)

最后 - 我有点同意@tbreloff上面的观察......二进制?是最紧凑的语法(这个线程的重点是制作紧凑的语法),我总是发现if是生成器过滤的一个有点令人惊讶的选择。

@StefanKarpinski写道:

Perl/Ruby 风格的 if/for 修饰符语法似乎会更好地与此混合。 换句话说:
julia println("positive") if x > 0 # conditional execution x^2 for x=1:100 # generator [ x^2 for x=1:100 ] # comprehension x^2 if x % 3 == 0 for x = 1:100 # filtered generator [ x^2 if x % 3 == 0 for x = 1:100 ] # filtered comprehension
它还具有在其他语言中具有先例的好处,而 if-then without end 语法似乎没有。

这对语法也会更好。

我认为[x^2 if x % 3 == 0 for x = 1:100]应该是:

[(x^2 if x % 3 == 0) for x = 1:100]
 ```
Then `for` stay's in infix position which is currently an error. Of course we can change its meaning because of leading `[` but it would not work as generator:
```julia
x^2 if x % 3 == 0 for x = 1:100

我认为[x^2 if x % 3 == 0 for x = 1:100]应该是:

那将不是过滤生成器。 当x为真时, 2 if x返回2 ,但当x为假时,它也必须返回一些东西; 通常是nothing 。 所以这会给出一个数字数组和什么都没有。 这也是过滤生成器语法中if必须在for之后的部分原因。

是的,你是对的。 也许应该这样写:

[for x = 1:100 x^2 if x % 3 == 0]

Afaics,这将是有效的可解析而不使用括号,酷!

只是想...

[ for x = 1:100 if x % 3 == 0 push x^2]
for x = 1:100 if x % 3 == 0 push x^2  # other keyword could be used, e.g. yield

这更类似于自然构造

for x=1:100 
    if x%3==0 
          push!(somearray, x^2)
    end
end

我刚刚在看别的东西时又看到了这个朱利酒。

我仍然希望像if a then b单行形式; 我确实发现 julian 替换a && b即使在使用了几年后也相当难以理解:没有办法直接将其作为英文句子阅读。

我还觉得需要向新手解释a && b习语有点尴尬,因为我们可以有一个不言而喻的替代语法,而且只需要更长的时间。

只是没有办法直接把它读成英文句子

a && b读作“a and b”,如“if a then also do b”
a || b读作“a 或 b”,如“a 必须为真,否则为 b”

我知道它的作用,为了简洁起见,我有时会使用它。 但是尽我所能(如前所述,几年来)我不能将“a和b”视为一个句子。 每次都只是轻微的认知失调。

相比之下,我总是发现“a 或 b”是相当可读的。

有趣的是,这方面的不同方面今天在工作中出现了两次

早上,我们有一个使用&&而不是if ... end的 Julia PR,我指出,作为一名代码阅读器(PR 审阅者),它需要额外的努力(并且很容易错过) 可能会或可能不会执行的分支。 这个例子是a() && b!() ,其中b!是极度变异的。 (在这种情况下, b!()移动或删除了文件系统中的文件,这似乎立即很危险,但我的大脑无法完全弄清楚这只有在!a()和这种情况下才有问题实际上得到了正确的防范)。

下午,另一位软件工程师(不认识 Julia)指出,与朋友说英语时,有时他会回答“是a还是b ” 回复“是”。 只有他的软件工程师的朋友会明白-其他人就一点看不懂。 正常人只是不这么想。 🙂 这有点与我的下一点有关(编辑:我应该说,与上面 Stefan 的回应有关,对于许多人来说,我认为他们不会发生这种情况)。

我一直以来对这个问题的立场是,使用&& (或|| )是一种简短的分支语法,只有具有强大 PL 背景的人才能阅读,即使这样也会添加一些认知/视觉负荷(只是区分&&& )。 我觉得在多学科团队(科学家和软件工程师的混合体)中工作时,半数团队都会感到困惑。 即使作为一名软件工程师,我也觉得我们在逻辑&(::Bool, ::Bool) --> Bool和分支&&(::Bool, ::Any) --> Any之间存在奇怪的脱节(是的,后者实际上不是一个函数,但希望你明白我的意思) . 除了类型本身,在 Julia 中,我通常期望前者是“功能性的”,而后一种形式通常涉及潜在的副作用——尤其是在第二个表达式中。

编辑:多想一下,这里的问题完全是关于副作用和程序流程的。 这是很容易让大家理解的是“功能性”的使用&&是优化& 。 对于非纯表达式,它们完全不同是相对难以调和的。

在某些情况下,我认为if a then b的“优先级”更清晰:

guard && c += 1    # probably an error because it's parsed as (guard && c) += 1
guard && (c += 1)  # parentheses required 

if guard then c += 1  # no ambiguity here

编辑器中的语法突出显示也有助于在表达式的开头标记if

它还具有在其他语言中具有先例的好处,而没有end语法的if - then似乎没有。

应该注意的是, if-then-else语法有很多先例:

并且该语法可用于上述所有语言的单行代码。

我已经知道这个讨论一个小时了,如果有人提出这个建议,请原谅我。

在我看来,'&&' 和 '||' 的短路选项之所以使用,是因为我们想要一行中的简单 if 语句,没有分号。 但是短路似乎是一种解决方法,但会产生另一个问题:作为一个普通人,如果没有以前看过它,或者知道第二个表达式仅在必要时才被评估,就很难理解和解析该语法。 不直观的阅读(作为人类)似乎是由于短路的视觉和逻辑缺陷。 甚至似乎在知道它的含义之后,阅读它可能比应该的更难。

如果我没记错的话,这两个问题都可以用一个宏来解决:

@if条件结果

否定可以用 ! 之前的条件,或者一个@ifnot宏。 只是我,还是对计算机没有歧义,对人类来说易于阅读,并且全部在一条线上?

甚至似乎在知道它的含义之后,阅读它可能比应该的更难。

^ 我非常同意这一点。

@if条件结果

您已经可以执行以下操作,看起来几乎相同:

if condition result end

下面是完整的 if-then-else 语法的宏。 但是,由于ifelse是保留关键字,因此宏使用IfThenElse代替。

syntax_error() = error("Valid syntax is either `<strong i="20">@If</strong> cond Then ex` or `<strong i="21">@If</strong> cond Then ex1 Else ex2`")

function If(exprs...)
    n_args = length(exprs)

    if n_args == 3
        if exprs[2] != :Then
            syntax_error()
        end

        ex = quote
            if $(exprs[1])
                $(exprs[3])
            end
        end
    elseif n_args == 5
        if ( exprs[2] != :Then ) || ( exprs[4] != :Else )
            syntax_error()
        end

        ex = quote
            if $(exprs[1])
                $(exprs[3])
            else
                $(exprs[5])
            end
        end
    else
        syntax_error()
    end

    return esc(ex)
end

macro If(exprs...)
    If(exprs...)
end

foo(x) = <strong i="22">@If</strong> x > 0 Then println("greater than zero") Else println("less than zero")

在这里我们可以看到foo的作用:

julia> foo(3)
greater than zero

julia> foo(-3)
less than zero

我更喜欢类似的东西

x0 = 1
x1 = 2
x3 = 3 when y>0  # y>0 is evaluated first
x4 = 4

when的优先级低于 = 并且从右到左操作。

您已经可以执行以下操作,看起来几乎相同:

if condition result end

我不知道! 我总是认为那个人需要通常有换行符的分号。 所以就我而言,语法

if condition result end

完全使&&的使用变得多余,所以没有问题! 我看到一个甚至可以执行以下操作:

if condition result_1 else result_2 end

在这种情况下,添加关键字end可能比制作宏更容易。 但是感谢您抽出时间来制作它^_^ 在文档中添加单行 if 语句的可能性是一个好主意吗? 我看到如果一个人做?If<enter>结果已经很多行了......但我觉得这个功能应该更多地宣传。

回顾最初的讨论,我赞成添加“If x then y”,尽管我发现它与“if”的单行版本有点多余。 但是,嘿,编写对您有意义的代码,对吧?

此页面是否有帮助?
0 / 5 - 0 等级