2017-01-20 4 views
2

У меня есть файл OptionList.hs с новым типом данных с именем OptionList. Я хочу, чтобы скрыть EmptyOpt когда OptionList предъявляется:Наложение перекрытий, почему это происходит?

module OptionList (
    OptionList, 
    voidOption, 
    (+:) 
) where 


data OptionList a b = EmptyOpt | OptionList { optListHead :: a, optListTail :: b } deriving (Read) 

instance (Show a, Show b) => Show (OptionList a b) where 
    show (OptionList voidOption a) = "{" ++ (show a) ++"}" 
    show (OptionList a voidOption) = "{" ++ (show a) ++"}" 
    show (OptionList a b) = "{"++ (show a) ++ ", " ++ (show b) ++"}" 
    show voidOption = "" 




voidOption::(OptionList Int Int) 
voidOption = EmptyOpt 



(+:) :: a -> b -> (OptionList a b) 
infixr 5 +: 
t1 +: t2 = OptionList t1 t2 

И тогда я главный файл todo.hs

import OptionList 


main = do 
    print (0 +: "test" +: voidOption) 

Но компилятор говорит, что шаблон согласования в OptionList.hs накладываются друг на друга:

OptionList.hs:12:9: Warning: 
    Pattern match(es) are overlapped 
    In an equation for ‘show’: 
     show (OptionList a voidOption) = ... 
     show (OptionList a b) = ... 

И когда я его выполняю, он действительно перекрывается. Он производит следующий вывод:

{{}} 

(Я хотел, чтобы это было {0, {"test"}})

Но почему эти картины перекрывающихся?

ответ

8

В строке

show (OptionList voidOption a) = "{" ++ (show a) ++"}" 

voidOption свежая локальная переменная, как a есть. Он не имеет отношения к переменной voidOption, определенной ниже. По существу, приведенная выше линия эквивалентна

show (OptionList b a) = "{" ++ (show a) ++"}" 

Следовательно, она всегда совпадает и перекрывается следующими строками.

Это легко запомнить, если мы рассматриваем все переменные в шаблонах как переменные , определенные шаблоном. В некотором смысле они представляют собой ценности, выходящие из шаблона, а не «в».

Включение предупреждений (-Wall) должно предупредить вас об этой ошибке, поскольку новая локальная привязка для voidOption затеняет глобальную.

В шаблонах вместо этого вы должны использовать конструктор EmptyOpt. Например.

show (OptionList EmptyOpt a) = "{" ++ (show a) ++"}" 
+0

Спасибо! Я обновил код, как было предложено, но появилось больше ошибок. См. Мое редактирование –

+0

@ BrunoCorrêaZimmermann. «Обновление» было бы лучше как новый вопрос, так как речь идет о новой проблеме с новым кодом. Но небольшой намек: в реализации 'show' у вас есть два произвольных типа' a' и 'b', и все, что вы знаете, это то, что они могут быть' show'n. Почему вы думаете, что вы можете сопоставить их шаблону с конструктором типа «OptionList»? – amalloy

+2

Хорошо! Сожалею. Я сделаю новый вопрос –