Я просто заметил, пытаясь научиться читать GHC Core, что
автоматически созданный экземпляр Eq
для типов данных типа enum, таких как
data EType = ETypeA | ETypeB | ETypeC | ETypeD
| ETypeE | ETypeF | ETypeG | ETypeH
deriving (Eq)
кажется, преобразуется в O (N) -подобный поиск при просмотре представления ядра GHC:
$fEqEType_$c== =
\ (a_ahZ :: EType) (b_ai0 :: EType) ->
case a_ahZ of _ {
ETypeA ->
case b_ai0 of _ {
ETypeA -> True;
ETypeB -> False;
ETypeC -> False;
ETypeD -> False;
ETypeE -> False;
ETypeF -> False;
ETypeG -> False;
ETypeH -> False
};
ETypeB -> case b_ai0 of _ {__DEFAULT -> False; ETypeB -> True};
ETypeC -> case b_ai0 of _ {__DEFAULT -> False; ETypeC -> True};
ETypeD -> case b_ai0 of _ {__DEFAULT -> False; ETypeD -> True};
ETypeE -> case b_ai0 of _ {__DEFAULT -> False; ETypeE -> True};
ETypeF -> case b_ai0 of _ {__DEFAULT -> False; ETypeF -> True};
ETypeG -> case b_ai0 of _ {__DEFAULT -> False; ETypeG -> True};
ETypeH -> case b_ai0 of _ {__DEFAULT -> False; ETypeH -> True}
}
Я неправильно истолковал вывод ядра GHC? Должны ли алгебраические типы данных предоставлять целочисленный идентификатор для каждого конструктора, который затем можно сравнивать непосредственно в O (1)? Кроме того, почему предложение первого случая для ETypeA
не использует __DEFAULT
, как это делают другие предложения?
обновление:
Согласно предложению Саймона Марлоу, я добавил 9-й конструктор ETypeI
, а затем GHC переключился на использование dataToOtag#
:
$fEqEType_$c/= =
\ (a_ahS :: EType) (b_ahT :: EType) ->
case dataToTag# @ EType a_ahS of a#_ahQ {
__DEFAULT ->
case dataToTag# @ EType b_ahT of b#_ahR {
__DEFAULT ->
case ==# a#_ahQ b#_ahR of _ {
False -> True; True -> False
}
}
}
Для меня это добавляет вопрос о том, какие компромиссы между ядром GHC case
и использованием dataToTag#
, и почему это конкретное отсечение 9 конструкторов для использования dataToTag#
реализовано в GHC.