2017-10-11 142 views
6

Preludenull函数的定义如下:为什么Haskell Prelude中的null函数的定义很奇怪?

null    :: [a] -> Bool 
null []   = True 
null (_:_)  = False 

什么让我感到困惑的是定义的第三行,为什么不把它写:

null(_:_)  = False 

相反的:

null any = False 

它与编译器优化有什么关系?

+1

没有。没关系。这个定义非常清楚地表明,没有错过任何东西,但对于那些实际上并不重要的列表。 – dfeuer

+1

另外,你可以定义'null = all(const False)'。也许这会更清楚。 – dfeuer

回答

5

它与编译器优化有什么关系?

非也,其实可以说,写null (_:_)null any效率更低(如果编译器不优化了这一点),因为现在你问哈斯克尔验证它确实是一个“缺点”。虽然如果编译器在数据类型上做了一些簿记,那么优化它当然很容易。据我所知,大多数编译器如ghc和差不多所有不是由三岁孩子编写的编译器确实会这样做。所有的

首先,它是更好的写wilcard _(或命名any),因为列表的定义(以及任何其他数据类型可能会改变)。虽然列表的可能性不大,但有人可能会重新定义一个列表。例如,如:

data [a] = [] | (a:[a]) | (Int///[a]) 

其中例如后一种模式意味着该列表重复多次。在那种情况下,一个不是由三岁小孩编写的编译器:)将警告大约对于null不完整的模式:它将因此声称(_///_)模式未被指定。而如果您使用通配符,它​​将回退到null any的情况。

一般来说,最好小心使用通配符:只有当你真的不关心给函数赋予什么时,你应该使用通配符。

+4

它*效率不高。编译器*总是*优化这个。 – dfeuer

+2

@dfeuer:这是一个奇怪的说法,因为没有提到具体的编译器。有朝一日,我可以编写一个Haskell编译器,但不这样做。我的说法并不是一个好的编译器不会优化这个。这个想法只是在语法上,前者效率较低。 :) –

+0

没有“语法上效率较低”这样的事情。具有代数数据类型的静态类型语言的体面编译器始终在这方面做得很好。请记住,编译器必须检查每个构造函数是否具有正确的类型;虽然它在,它可以很容易地检查所有的存在。这对于GADT来说要复杂得多,但这些在这里并不相关。 – dfeuer

相关问题