2013-06-23 4 views
9
take :: Int -> [a] -> [a] 
genericTake :: Integral i => i -> [a] -> [a] 

Я читал, что неудобный тип take объясняется историческими причинами, и это изменение может привести к разрыву кода.Почему нельзя использовать тип принятия, чтобы использовать какой-либо интеграл?

Но я не могу заменить take на genericTake везде, не нарушая ничего? В чем проблема?

+0

Я предполагаю, что может возникнуть ситуация, когда вывод типа основан на 'take' type - с' genericTake' что-то типа «не может выводиться» будет происходить. – leventov

+4

Обратите внимание, что в дополнение к (и, возможно, более существенному, чем) поломке кода в неясных случаях замена 'take' на' genericTake' приведет к ухудшению производительности во многих случаях (так как тип defaulting теперь приведет к 'Integer', используется, когда не указывается ':: Int'). – sepp2k

ответ

10

распадающейся случай

genericTake :: Integral i => i -> [a] -> [a] 
genericTake n xs = take (fromIntegral n) xs 

class Foo a where 
    bar :: a -> String 

instance Foo Int where 
    bar _ = "int" 

foo :: String -> [a] -> [a] 
foo ns xs = let y = read ns 
       z = bar y 
      in take y xs 

Это будет перерыв genericTake.

No instance for (Foo i0) arising from a use of `bar' 
    The type variable `i0' is ambiguous 

Это состряпали пример, но вы можете понять, какой тип логического вывода, протекающие на первый аргумент дубля, где предполагается, что Int, теперь, когда вы измените тип на Integral i => i некоторые проблемы могут возникнуть, как указано выше.

+0

+1 Это настоящая боль с экземплярами типа, и я бы хотел, чтобы она была исправлена. – jpaugh

+0

@jpaugh Что вы предлагаете, это исправление? Я не уверен, что это можно исправить. – Satvik

+0

Не пробовал это, но разве это не скомпилировано с расширенными правилами дефолта? –