Din*_*cio 20 haskell functional-programming pattern-matching raku
Haskell 和 Rust(以及我不知道的其他语言)有一个他们称之为“模式匹配”的发展。下面是 Haskell 中的一个例子:
data Event = HoldKey Char | PressKey Char | Err String
someFunc = let
someEvent <- doSomeStuff
-- What follows is a case expression using pattern matching
thingINeed <- case someEvent of
HoldKey keySym -> process keySym
PressKey keySym -> process keySym
Err err -> exit err
in keepDoingStuff
Run Code Online (Sandbox Code Playgroud)
在 Raku 中与此最接近的似乎是 多方法 multifunctions(术语在下面的答案中固定,但 multimethods 也可以工作)。
class Hold { has $.key; }
class Press { has $.key; }
class Err { has $.msg; }
multi process(Hold (:$key)) { say $key; }
multi process(Press (:$key)) { say $key; }
multi process(Err (:$msg)) { say $msg; }
Run Code Online (Sandbox Code Playgroud)
但是,如果我想要一个“本地”模式匹配表达式(如case上面 haskell 片段中的表达式),这无济于事。像这样的东西:
given Hold.new(:key<a>) {
when Hold (:$key) { say $key }
when Press (:$key) { say $key }
when Err (:$msg) { say $msg }
default { say "Unsupported" }
}
Run Code Online (Sandbox Code Playgroud)
唉,不能编译。那么我是不是遗漏了什么,或者 Raku 可以用其他方式表达吗?
Bra*_*ert 13
您正在尝试使用不需要签名的签名。
签名更有可能是块的一部分,所以它看起来更像这样:
given Hold.new(:key<a>) {
when Hold -> (:$key) { say $key }
when Press -> (:$key) { say $key }
when Err -> (:$msg) { say $msg }
default { say "Unsupported" }
}
Run Code Online (Sandbox Code Playgroud)
这目前不起作用,因为块没有任何参数。
可以说这将是一个有用的添加功能。
请注意,只有两件事可以given做。
proceed并succeed最终确定。$_为您提供的值。所以这意味着它$_已经设置为您正在智能匹配的值。
given Hold.new(:key<a>) {
when Hold { say .key }
when Press { say .key }
when Err { say .msg }
default { say "Unsupported" }
}
Run Code Online (Sandbox Code Playgroud)
cod*_*ons 10
您尝试的语法实际上非常接近。这是你想要的:
class Hold { has $.key; }
class Press { has $.key; }
class Err { has $.msg; }
given Hold.new(:key<a>) {
when Hold { say .key }
when Press { say .key }
when Err { say .msg }
default { say "Unsupported" }
}
Run Code Online (Sandbox Code Playgroud)
需要注意的几件事:正如语法中的变化所示,您正在匹配的类型Hold,但您不是在解构 Hold。相反,您正在利用when块将块内的主题变量 ( $_)设置为等于匹配这一事实。
其次(看起来您已经意识到这一点,但我正在添加它以供将来参考),重要的是要注意given块并不能保证详尽的模式匹配。您可以使用default { die }块模拟该保证,但这当然是运行时检查而不是编译时检查。
rai*_*iph 10
我同意在 Raku 中有优雅的语法会很好。但从功能上讲,我认为 Raku 比您想象的更接近您所描述的内容。
Raku 中与此最接近的似乎是多方法。
Raku 确实支持多种方法。但是你展示的是多功能的。
我也认为多功能是 Raku 目前最接近你描述的东西。但我也认为它们比你目前认为的更接近。
我想要一个“本地”模式匹配表达式
多功能是本地的(词法范围)。
class Hold { has $.key; }
class Press { has $.key; }
class Err { has $.msg; }
{
match Hold.new: :key<a> ;
multi match (Hold (:$key)) { say $key }
multi match (Press (:$key)) { say $key }
multi match (Err (:$msg)) { say $msg }
multi match ($) { say "unsupported" }
}
# match; <--- would be a compile-time fail if not commented out
Run Code Online (Sandbox Code Playgroud)
是的,上面的代码在语法上是“关闭的”。假设 RakuAST 登陆它可能会特别直接地实现更好的语法。也许:
match Hold.new: :key<a>
-> Hold (:$key) { say $key }
-> Press (:$key) { say $key }
-> Err (:$msg) { say $msg }
else { say "unsupported" }
Run Code Online (Sandbox Code Playgroud)
wherematch实现了multi我上面显示的代码,但是:
避免需要封闭块;
避免需要显式编写函数调用;
替代对象multi match(...)样板相对简洁->。
让else条款强制性的(为了避免歧义的语法,但有执行失败的显式处理以其他方式匹配的很好的副作用)。
我注意到你为你的例子引入了 OO。(并称为多功能 multimethods。) 需要明确的是,您不需要使用对象来使用 Raku 中的签名进行模式匹配。