当前位置:  开发笔记 > 编程语言 > 正文

Haskell:未定义值的模式匹配

如何解决《Haskell:未定义值的模式匹配》经验,为你挑选了2个好方法。

据我了解,Haskell的undefined值 - 特定类型 - 是一个无法确定的值,无论出于何种原因(可能没有合理的定义,或者计算方法不同).例如:undefined :: [Int]是一个列表,所以它必须用[]或(:)构造,但它不知道哪一个!因此,有意义的是,未定义的案例拆分使得整个表达式未定义:我不知道null (undefined :: [a])是真还是假,因为我不知道是否undefined :: [a]为空.

(顺便说一句-如果你用我的建议,不同意undefined 建有一个构造函数,那么肯定null (undefined :: [a])应该评估为False毕竟?undefined不等同于[]!)

但是,Haskell模式匹配并不遵循这种思维方式.

data Foo = Foo Int String  -- Only one data constructor

silly :: Foo -> Bool
silly (Foo _ _) = True

ghci> silly (undefined :: Foo)
*** Exception: Prelude.undefined    -- But whatever the value is, it must 
                                    -- be constructed with Foo.
                                    -- So why fail to match?

(我知道newtype在这里表现不同.)

也:

foo :: Int -> String -> Bool
foo 8 "Hello" = True
foo _ _       = False

ghci> foo undefined undefined
*** Exception: Prelude.undefined     -- GOOD - can't tell which case to choose.

ghci> foo undefined "Hello"
*** Exception: Prelude.undefined     -- GOOD - still can't tell.

ghci> foo undefined "Goodbye"
*** Exception: Prelude.undefined     -- BAD  - should return false!
                                     -- Pattern match on first line should fail,
                                     -- because whatever the int is, the
                                     -- string can't match the given pattern.

我认为关于模式匹配的规则目前说如果子模式失败那么模式应该立即失败; 如果它发散,那么整个模式也应该分歧; 如果成功,则应尝试下一个子模式.如果所有子模式都成功,则整个模式成功.

我的建议是,如果任何子模式失败,那么整个模式应该失败; 如果没有失败,但有些分歧,那么整个模式应该分歧; 如果一切顺利,那么整个模式应该成功.

为什么这不是Haskell的工作方式?


编辑:

总结一下我对我读过的回答的解释:

undefined应该被理解为"这将导致你的程序永远运行"而不是"这个定义不明确",Exception: Prelude.undefined应该被理解为"注意!如果未定义是一个无限循环你的程序将永远不会终止"而不是"我不要不知道该怎么办,因为我不知道undefined是什么价值".

有人可以验证这是正确的吗?如果是这样,那么我可能会接受mb14的回答.

感谢大家.对不起因为速度太慢了!



1> mb14..:

基本上,你是说undefined :: FooFoo undefined undefined,因为(你说的应该是相同的But whatever the value is, it must be constructed with Foo.).

这种假设是不正确的.富必须与构造Foo,只有当它能够建造.如果我有foo = if x then (Foo 1 "a") else (Foo 2 "b").如果x未定义则尝试评估f分歧.那时,没有构造函数的概念.它只是分歧.

这是你的榜样一样null (undefined :: [a])应该是undefined(发散),以及因为你需要尝试评估的参数null就知道如果它是一个[]或一个:.

在Haskell中未定义并不神奇,它只是一个循环.你可以定义自己的loop = let x = x in x.每次尝试评估它时都会循环.调用null loopsill loop将循环因此等于loop,不是吗?你还在考虑那个loop :: Foo并且Foo loop loop是一样的吗?我不.我希望silly loop循环但不是silly (Foo loop loop).

这之间的唯一区别loop,并undefined仅仅是GHC可以检测undefined是一个循环,并因此打破了外观和显示错误消息,而不是无休止的循环下去的.它只是为了方便,如果不存在,人们会定义undefined = loop.


@RhubarbAndC这是对'undefined`的合理解释.另一个可能是"这应该永远不会发生!中止程序"或甚至"这没有实施 - 中止".

2> Alexey Roman..:

(顺便说一句 - 如果你不同意我的建议,undefined是用构造函数构建的,那么肯定null(undefined :: [a])应该计算为False吗?毕竟undefined不等于[]!)

这意味着它不应该评估True,也不应该评估.

我的建议是,如果任何子模式失败,那么整个模式应该失败; 如果没有失败,但有些分歧,那么整个模式应该分歧; 如果一切顺利,那么整个模式应该成功.

怎么能实现呢?要查找第一个子模式是否失败,您需要评估该参数; 如果它发散,评估将无法完成,整个模式匹配也会因定义而异.您可以尝试"并行"评估所有模式,但这会使语言复杂化:当前定义将多个方程式转换case为第一个参数,然后是第二个参数,等等,因此它不会介绍任何新概念; 你的必须.

我不会说" undefined应该代表一个非终止计算",但你不应该能够区分它们:

Haskell中的错误在语义上等同于⊥("bottom").从技术上讲,它们与不确定无法区分,因此该语言不包括检测错误或对错误采取行动的机制.但是,实现可能会尝试提供有关错误的有用信息.见3.1节.

推荐阅读
mobiledu2402851373
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有