彻底解构 SML 中的列表
Exhaustively destructuring lists in SML
SML 片段 ... let val (x::xs) = String.explode s in ...
总是会抱怨模式不够全面,即使我在函数定义中对空字符串大小写进行模式匹配。有什么方法可以修改它,使匹配详尽无遗吗?
您必须使用 case
而不是 let
:
... case String.explode s of x::xs => ... | nil => raise Domain
或者,如果您绝对想保留 let
,请将其变成一对:
val (x, xs) = case ... of x::xs => (x, xs) | nil => raise Domain
你可以将后者抽象成辅助函数:
fun decons (x::xs) = (x, xs)
| decons nil = raise Domain
let val (x::xs) = ...
之所以不详尽,是因为 val
声明只有一个模式占位符(此处用于 x::xs
)。列表作为一种求和类型,有两个构造函数,::
和[]
。正如 Andreas Rossberg 所说,case
是当你有多个模式时要走的路。请参阅 进行自以为是的比较(TL;DR:我有时喜欢使用 case
,即使只有一种情况。)
[...] even if I pattern-match the empty string case in the function definition
您可以考虑删除空字符串大小写,对所有输入调用 String.explode
并以与处理空字符串大小写相同的方式处理 []
的输出。
所以下面的代码:
fun f "" = <foo>
| f s = case String.explode s of
x::xs => <bar>
| [] => raise Fail "impossible"
变为:
fun f s = case String.explode s of
[] => <foo>
| x::xs => <bar>
SML 片段 ... let val (x::xs) = String.explode s in ...
总是会抱怨模式不够全面,即使我在函数定义中对空字符串大小写进行模式匹配。有什么方法可以修改它,使匹配详尽无遗吗?
您必须使用 case
而不是 let
:
... case String.explode s of x::xs => ... | nil => raise Domain
或者,如果您绝对想保留 let
,请将其变成一对:
val (x, xs) = case ... of x::xs => (x, xs) | nil => raise Domain
你可以将后者抽象成辅助函数:
fun decons (x::xs) = (x, xs)
| decons nil = raise Domain
let val (x::xs) = ...
之所以不详尽,是因为 val
声明只有一个模式占位符(此处用于 x::xs
)。列表作为一种求和类型,有两个构造函数,::
和[]
。正如 Andreas Rossberg 所说,case
是当你有多个模式时要走的路。请参阅 case
,即使只有一种情况。)
[...] even if I pattern-match the empty string case in the function definition
您可以考虑删除空字符串大小写,对所有输入调用 String.explode
并以与处理空字符串大小写相同的方式处理 []
的输出。
所以下面的代码:
fun f "" = <foo>
| f s = case String.explode s of
x::xs => <bar>
| [] => raise Fail "impossible"
变为:
fun f s = case String.explode s of
[] => <foo>
| x::xs => <bar>