2016-07-24 4 views
2

Я изучаю Haskell. Это тривиальный пример, но я хотел бы понять концепцию, почему я не могу использовать сопоставление шаблонов внутри лямбда-функции в следующем примере (т. Е. Почему функция filterfold работает, но filterfold) дает ошибку времени выполнения:Соответствие шаблону внутри lambda

-- Runs 
filterfold' :: (a -> Bool) -> [a] -> [a] 
filterfold' p zs = foldr (\y zs -> if (p y) then y:zs else zs) [] zs 

-- Runtime error: Non-exhaustive patterns in lambda 
filterfold :: (a -> Bool) -> [a] -> [a] 
filterfold p (z:zs) = foldr (\y (z:zs) -> if (p y) then y:(z:zs) else (z:zs)) [] (z:zs) 

ответ

4

вы можете использовать его, но так как компилятор говорит вам, что вы пропускаете случай (когда вход [])

Смотрите, если вы говорите, z:zs он будет пытаться соответствовать этому шаблону с входным списком - если вы

  • ввод [1,2,3] = 1:[2,3] вы получите z=1 и zs=[2,3]
  • , но когда вход [] вы не можете получить z и zs так что z:zs = [] (технически они основаны на различных конструкторами-списка типов данных)

Так во время выполнения он не будет знать, как обрабатывать этот случай/шаблон, когда он видит [] и выдаёт исключение.

, если вы внимательно посмотрите на вашем примере вы должны увидеть, что вы никогда не использовать детали в любом случае (то есть z или zs - вы только использовать их в качестве z:zs снова), поэтому я не могу сказать вам, как сделать это лучше

в любом случае вы можете использовать case - выражение внутри от лямбда:

... = foldr (\ x zs = case zs of 
         z:zs -> ... 

или вы можете использовать расширение LambdaCase, чтобы сделать его немного короче.

+0

Итак, zs из аргумента функции filterfold находится в области видимости, но вместо того, чтобы использовать 'z' из filterfold, он пытается выполнить локальное соответствие шаблона внутри лямбда? – Daniel

+1

Да 'z' и' zs' внутри лямбда будут разными ('foldr' будет * предоставлять * их) - вот почему вы не должны повторно использовать имена параметров/аргументов для лямбда-аргументов - вы * вводите * те имена с ваш лямбда и скроет один раз из внешней области - поэтому, если вы хотите (повторно) использовать 'z' и' zs' из внешней области в 'filterfold', вы должны просто переименовать его в' foldr (\ y ys -> ...) '(или любое другое имя, отличное от' p', 'z',' zs' и 'y';)) – Carsten

+0

, но обратите внимание: если вам действительно не нужен второй аргумент функцию (лямбда), которую вы даете 'foldr', то вам, вероятно, не нужно' foldr' в первую очередь, поскольку вы действуете только на 'head' списка, если это не пусто или не соответствует второму аргумент 'foldr' – Carsten

Смежные вопросы