Определение степени ленивой оценки

Дано

data BTree a = End
             | Node a (BTree a) (BTree a)
   deriving(Show,Eq,Ord)

data Msg = Msg { from :: String
               , to :: String
               , when :: Int
               , message :: String }

instance Ord Msg where
    compare a b = (when a) `compare` (when b)

instance Eq Msg where
    (==) a b = (when a) == (when b)

Моя функция для подсчета узлов (что кажется неправильным, но это не вопрос)

count :: (Ord a) => (BTree a) -> Int
count = sum . count'
 where
  count' :: (Ord a) => (BTree a) -> [Int] 
  count' End = []
  count' (Node _ l r) =
    [1] ++ (count' l) ++ (count' r)

Разве count не оценивает содержимое Msg на основании того, что его значение отбрасывается _? Возможно, лучше спросить, как мне узнать, где начинается и заканчивается ленивая оценка для такого рода вещей?

Если бы третья строка count' была:

count' (Node (Msg x _ _ _) l r) =

Могу ли я предположить, что другие три поля Msg были доступны/оценены, или ленивая оценка зашла так далеко?


person clintm    schedule 10.10.2011    source источник
comment
Нет. Другие поля не оцениваются. Вы можете поместить челку ((Node (Msg x !_ !_ !_) l r) для принудительной оценки. Включить шаблоны челки с помощью прагмы {-# LANGUAGE BangPatterns #-}   -  person fuz    schedule 10.10.2011
comment
При сопоставлении с образцом элементы оцениваются только для сопоставления с образцом. И, таким образом, в случае _ он соответствует чему угодно, поэтому ничего не будет оцениваться.   -  person is7s    schedule 10.10.2011
comment
@is7s, спасибо! В этом был корень, хотя и не очень хорошо выраженный, моего вопроса.   -  person clintm    schedule 10.10.2011


Ответы (1)


Нет. Поля структуры данных по умолчанию обрабатываются лениво. Поскольку вы никак не используете другие поля, они не будут оцениваться этим кодом. Если вы хотите сделать так, чтобы оценка узла заставляла оценивать все его поля, вы можете добавить к полям аннотации строгости:

data BTree a = End
             | Node !a (BTree a) (BTree a)
   deriving(Show,Eq,Ord)

data Msg = Msg { from :: !String
               , to :: !String
               , when :: !Int
               , message :: !String }

Поскольку подсчет узлов приводит к оценке самих узлов, это также приводит к оценке значений узлов. Если вам нужно такое поведение только для одной вашей функции, вы можете принудительно выполнить более точную оценку, используя seq:

count' (Node x l r) = x `seq` ([1] ++ count' l ++ count' r)

или узор челки (требуется расширение BangPatterns)

count' (Node !x l r) = [1] ++ count' l ++ count' r
person hammar    schedule 10.10.2011
comment
Потрясающий! Я надеялся, что это так. Суть вопроса заключалась в том, что я планирую использовать это в долгоиграющей программе, и я хотел убедиться, что такие функции, как count, не потребляют больше памяти, чем это абсолютно необходимо. - person clintm; 10.10.2011
comment
Строгие поля String (или шаблоны челки на Strings) будут оценивать только String достаточно, чтобы узнать, является ли это [] или _:_: f (Msg _ _ _ _) = (); print (f (Msg "from" "to" 0 ('c':error "1"))) {- ok -}; print (f (Msg "from" "to" 0 (error "2"))) {- error -} - person FunctorSalad; 25.02.2012