在Prelude的null
函数的定义如下:为什么Haskell Prelude中的null函数的定义很奇怪?
null :: [a] -> Bool
null [] = True
null (_:_) = False
什么让我感到困惑的是定义的第三行,为什么不把它写:
null(_:_) = False
相反的:
null any = False
它与编译器优化有什么关系?
在Prelude的null
函数的定义如下:为什么Haskell Prelude中的null函数的定义很奇怪?
null :: [a] -> Bool
null [] = True
null (_:_) = False
什么让我感到困惑的是定义的第三行,为什么不把它写:
null(_:_) = False
相反的:
null any = False
它与编译器优化有什么关系?
它与编译器优化有什么关系?
非也,其实可以说,写null (_:_)
比null any
效率更低(如果编译器不优化了这一点),因为现在你问哈斯克尔验证它确实是一个“缺点”。虽然如果编译器在数据类型上做了一些簿记,那么优化它当然很容易。据我所知,大多数编译器如ghc
和差不多所有不是由三岁孩子编写的编译器确实会这样做。所有的
首先,它是更好的不写wilcard _
(或命名any
),因为列表的定义(以及任何其他数据类型可能会改变)。虽然列表的可能性不大,但有人可能会重新定义一个列表。例如,如:
data [a] = [] | (a:[a]) | (Int///[a])
其中例如后一种模式意味着该列表重复多次。在那种情况下,一个不是由三岁小孩编写的编译器:)将警告大约对于null
不完整的模式:它将因此声称(_///_)
模式未被指定。而如果您使用通配符,它将回退到null any
的情况。
一般来说,最好小心使用通配符:只有当你真的不关心给函数赋予什么时,你应该使用通配符。
没有。没关系。这个定义非常清楚地表明,没有错过任何东西,但对于那些实际上并不重要的列表。 – dfeuer
另外,你可以定义'null = all(const False)'。也许这会更清楚。 – dfeuer