2015-11-04 3 views
6

Функция ниже должна генерировать простые числа, однако это не относится к GHC 7.10.2. Кто-нибудь еще видит это?nubBy не работает должным образом

GHCi, version 7.10.2: http://www.haskell.org/ghc/ :? for help 
Prelude> import Data.List 
Prelude Data.List> print . take 100 . nubBy (\x y -> x `rem` y == 0) $ [2..] 
[2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101] 

Странная часть является то, что, кажется, работает хорошо на этом сайте:

rextester.com/LWZCQ71376

+3

'nubBy' требует отношения эквивалентности, я думаю. – chi

+2

Это то, что говорят документы, и функция, переданная здесь, не является, что приведет к неопределенному поведению. На практике это может быть, например, были переписаны таким образом, что аргументы применяются в обратном порядке (безопасны для функций эквивалентности, а не для таких произвольных функций, как это) –

+0

Он работает здесь отлично: http://rextester.com/LWZCQ71376 –

ответ

14

Что изменилось между базовой 4.7.x и базовой 4.8.0.0 является определение elem_by, который является то, что nubBy определяется в терминах.

В базе-4,7 elem_by имеет этот пункт:

elem_by eq y (x:xs)  = y `eq` x || elem_by eq y xs 

и в базовой 4,8 оно было изменено на:

elem_by eq y (x:xs)  = x `eq` y || elem_by eq y xs 

История этого изменения документированы в этих вопросах ПРОФ:

Обратите внимание, что прелюдия версия Haskell Доклад nubBy является:

nubBy eq (x:xs)   = x : nubBy eq (filter (\ y -> not (eq x y)) xs) 

, который был в ссоре с реализацией базового 4.7, так что и объясняет изменения.

+0

Функция eq должна быть коммутативной, представляется возможным, что это изменение может стать причиной моей проблемы. –

+4

Нет !! Ваша функция 'eq' не является коммутативной! 'rem 4 2/= rem 2 4'. Один будет равен нулю, а другой будет равен двум. –

+5

Я думаю, что лучший термин для использования - _симметричный. – ErikR

3

Порядок аргументов был перевернут, кажется, на новой базе. EDIT: Я назвал это ошибкой, но, как еще один ответ, старое поведение было неправильным.

Вы можете увидеть порядок был перевернут, наблюдая:

> print . take 5 . nubBy (\x y -> trace (show (x,y)) $ x `rem` y == 0) $ [2..] 
[2(2,3) 
,3(3,4) 
(2,4) 
,4(4,5) 
(3,5) 
(2,5) 

Конечно rem 2 4 не равен нулю (он равен 2), таким образом, дает 4.

Уведомления вы получите результат вы хотите, когда вы щелкаете заказ аргумента в лямбда:

> print . take 5 . nubBy (\x y -> trace (show (x,y)) $ y `rem` x == 0) $ [2..] 
[2(2,3) 
,3(3,4) 
(2,4) 
(3,5) 
(2,5) 
.... 

EDIT: Поскольку обсуждение показывает соотношение должно быть равенство и действует независимо от того, (и я m ленив посмотреть отчет прямо сейчас), обратите внимание, что вы можете сравнить аргументы в первую очередь и получить стабильное поведение в любом случае:

print . take 100 . nubBy (\x y -> rem (max x y) (min x y) == 0) $ [2..] 
+0

Вы бы назвали это ошибкой в ​​базе GHC? –

+0

Конечно. Во-первых, определите «ошибку» как поведение, противоречащее спецификации языка Haskell. Во-вторых, обратите внимание, что это поведение было противоположным. В-третьих, крик «ошибка». –

+2

'(\ x y -> rem (max x y) (min x y) == 0)' может быть симметричным, но он все еще не является отношением эквивалентности. –