我想知道了解SML
中的模式匹配是否会继续发出Match
警告的最佳策略。
考虑以下功能:
fun f 7 (x,y) = x * 5.1 | f x (y,#"a") = y;
乍看之下,它似乎没有提供Match
警告。但是,如果我运行它,它将。
从我的角度来看,我们处理所有案件。我们不处理哪种情况?即使f 7 (x,#"a")
我们知道应该是哪种情况(第一个)。
我的问题是,如何确定该功能将输出该减弱的信号。
此外,我很乐意回答以下功能为何无效的问题:
fun f (x::xs) (y::ys) (z::zs) = y::xs::ys::zs;
没有zs
有效。 zs
如何进行更改?
答案 0 :(得分:0)
我的问题是,如何确定该功能将输出该减弱的信号。
编译器具有确定该算法的算法。
要么使用编译器并警告您,要么在脑海中使用类似的启发式方法。
请参见Luc Maranget(2007)的Warnings for pattern matching。
它涵盖了查找缺失和重复模式的问题,算法和实现。
一种有用的启发式方法:将线排列起来,例如喜欢:
fun fact 0 = 1
| fact n = n * fact (n - 1)
并问自己:是否存在值的组合,而该函数的一种情况并不能解决?每个功能用例都应解决输入的某些特定逻辑类别。由于您的示例不是实际示例,因此无法使用此方法,因为输入中没有逻辑类别。
fact
有点简单,因为非常容易确定它属于0
还是n
类别。
但是,值~1
是否正确地属于以下类别之一?
a practical example是有问题模式的函数:
fun hammingDistance [] [] = SOME 0
| hammingDistance (x::xs) (y::ys) =
if length xs <> length ys then NONE else
if x = y
then hammingDistance xs ys
else Option.map (fn d => d + 1) (hammingDistance xs ys)
似乎有两种逻辑情况:列表为空,或者不是:
输入列表为空,在这种情况下,第一个正文被激活。
输入列表不是空的,在这种情况下它们的长度是不同的或相等。
如果长度不同,请NONE
。
如果它们的长度相等,则计算距离。
当然,这是一个细微的错误,因为第一个列表可以为空,而第二个列表不为空,而第二个列表可以为空,而第一个列表不为空。如果是这种情况,则第二个主体永远不会受到撞击,而且永远不会区分不同/相等长度的物体。因为分类的任务是在模式匹配和 if-then-else 之间进行划分,并且优先于模式匹配。
我个人先发制人地解决此类问题的方法是这样思考:
当我在列表上进行模式匹配时(例如),我必须覆盖两个构造函数(1. []
,2。::
),而当我在两个列表上进行模式匹配,我必须介绍其构造函数的笛卡尔积(1. []
,[]
,2。[]
,::
,3。{{1 }},::
和4。[]
,::
)。
我只能计算两个模式/实体,没有一个可以涵盖四个案例中的一个,所以我知道我缺少一些。
如果有一个带有变量的案例,我必须问一下它涵盖了多少个常见案例。
::
这里只有三个图案/实体,但最后一个是万能的; fun hammingDistance (x::xs) (y::ys) =
if x = y
then hammingDistance xs ys
else Option.map (fn d => d + 1) (hammingDistance xs ys)
| hammingDistance [] [] = SOME 0
| hammingDistance _xs _ys = NONE
和_xs
匹配所有可能的列表,无论是空列表还是非空列表,除非它们首先与前面的模式之一匹配。因此,这第三种情况同时考虑了2. _ys
,[]
和3。::
,::
。
所以我不能简单地计算每个图案/身体一次。如果某些人通过模式变量包含非常通用的模式,则它们可能占一类以上的输入。如果它们通过多个构造函数包含过分具体的模式,则可能占用较少的总输入空间。例如
[]
这里的fun pairs (x::y::rest) = (x, y) :: pairs rest
| pairs [] = []
如此具体,以至于我没有涵盖仅一个元素的情况。