劈毛劈弦

Splitting hairs whilst splitting strings

我试着在 Idris 中创建一个函数,如下所示:

strSplit : String -> Maybe (Char, String)

这会将字符串 'un-cons' 分为第一个 Char 和字符串的其余部分,如果它是空的 return Nothing

所以我写了这个,但失败了:

strSplit x = case strM of
    StrNil       => Nothing
    StrCons c cd => Just (c, cs)

所以我尝试了这个,有点像 Prelude.Strings:

strSplit x with (strM x)
    strSplit ""             | StrNil         = Nothing
    strSplit (strCons c cs) | (StrCons c cs) = Just (c, cs)

编译和 运行 没问题。

我的问题是,为什么我必须使用 with 规则以这种方式拆分字符串,为什么我原来的方法会失败?

注意:抱歉,我暂时无法访问翻译,所以我还不能在这里写错误信息。

这里有两个问题。首先,在 'case' 块中,参数是 strM 而不是 strM x ,因为它在 'with' 块中,所以你正在检查不同的东西。

不过还有一个更有趣的问题,那就是如果您尝试修复第一个问题:

strSplit : String -> Maybe (Char, String)
strSplit x = case strM x of
    StrNil       => Nothing
    StrCons c cd => Just (c, cs)

你会得到一个不同的错误(这是来自当前的主人,它已经改写了错误信息):

Type mismatch between
    StrM "" (Type of StrNil)
and
    StrM x (Expected type)

所以 'case' 和 'with' 之间的区别是 'with' 考虑到您正在检查的东西可能会影响左侧的类型和值。在'case'中,匹配strM x意味着x必须是"",但是'case'可以出现在任何地方并且不考虑对类型的影响其他参数(为此制定适当的类型检查规则将是一个很大的挑战...)。

另一方面,'with' 只能出现在顶层:实际上它所做的是添加另一个顶层的东西来匹配,作为顶层,可以影响其他模式的类型和值。

所以,简短的回答是 'with' 支持依赖模式匹配,但 'case' 不支持。