Таким образом, хотя существуют функции, подобные сопоставлению с образцом, которые требуют Eq, они не сопоставляются с образцом и могут быть реализованы поверх сопоставления с образцом.

еделил двоичное дерево:

data Tree = Null | Node Tree Int Tree

и реализовали функцию, которая будет давать сумму значений всех ее узлов:

sumOfValues :: Tree -> Int
sumOfValues Null = 0
sumOfValues (Node Null v Null) = v
sumOfValues (Node Null v t2) = v + (sumOfValues t2)
sumOfValues (Node t1 v Null) = v + (sumOfValues t1)
sumOfValues (Node t1 v t2) = v + (sumOfValues t1) + (sumOfValues t2)

Работает как положено. У меня была идея также попытаться реализовать это с помощью охранников:

sumOfValues2 :: Tree -> Int
sumOfValues2 Null = 0
sumOfValues2 (Node t1 v t2)
    | t1 == Null && t2 == Null  = v
    | t1 == Null            = v + (sumOfValues2 t2)
    |               t2 == Null  = v + (sumOfValues2 t1)
    |   otherwise       = v + (sumOfValues2 t1) + (sumOfValues2 t2)

но этот не работает, потому что я не реализовалEq, Я верю:

No instance for (Eq Tree)
  arising from a use of `==' at zzz3.hs:13:3-12
Possible fix: add an instance declaration for (Eq Tree)
In the first argument of `(&&)', namely `t1 == Null'
In the expression: t1 == Null && t2 == Null
In a stmt of a pattern guard for
             the definition of `sumOfValues2':
        t1 == Null && t2 == Null

Тогда возникает вопрос: как Haskell может сопоставлять шаблоны, не зная, когда совпадает переданный аргумент, не прибегая кEq?

редактировать

Ваши аргументы, кажется, вращаются вокруг того факта, что Haskell на самом деле не сравнивает аргументы функции, а использует «форму» и типы подписи, чтобы узнать, какая подфункция должна соответствовать. Но как насчет этого?

f :: Int -> Int -> Int
f 1 _ = 666
f 2 _ = 777
f _ 1 = 888
f _ _ = 999

При бегеf 2 9разве не придется использоватьEq узнать, какая из подфункций является правильной? Все они равны (в отличие от моего первоначального примера Tree, когда у нас было Tree / Node / Null). Или это фактическое определениеInt что-то вроде

data Int = -2^32 | -109212 ... | 0 | ... +2^32 

?

 hvr18 янв. 2011 г., 12:07
Кстати, если вам нужноEq для сопоставления с образцом было бы довольно сложно определитьEq экземпляры на первом месте сами ... ;-)
 devoured elysium18 янв. 2011 г., 01:31
Да, я знаю. Но для контекста вопроса мне просто было все равно.
 sepp2k18 янв. 2011 г., 00:35
Когда вы сопоставляете шаблон с числами, вы используетеEq класс. Числовые литералы не являются конструкторами. Если бы они были, они не могли бы иметь типNum a => a, Обратите внимание, чтоNum требуетEq, Если вы определитеNum экземпляр с фанкомEq Например, сопоставление с образцом будет вести себя соответствующим образом (т.е. если(fromInteger 42 :: MyInt) == fromInteger 23 верно, шаблон23 также будет соответствовать значению42 :: MyInt).
 Wei Hu18 янв. 2011 г., 01:28
Как вы знаете, не все 32 бита доступны для представления Int. На моей машинеmaxBound :: Int возвращает 2147483647, 2 ^ 31 - 1.
 fuz18 янв. 2011 г., 12:18
@ Вей Ху: На самом деле, они делают. Подумайте об этом: maxBound = 2147483647 = 2 ^ 31 - 1, minBound = -2147483648 = 2 ^ 32, затем добавьте 0, и вы получите: 2 ^ 31 + 2 ^ 31-1 +1 = 2 ^ 32, что вы хочу больше?

Ответы на вопрос(7)

шаблон со значениемTreeскомпилированный код извлекает тег и просто знает, в какую ветку отправлять. Это не заботится о реальной стоимости, поэтому вам не нужноEq.

Внесколько Точка, вам нужно сопоставление с образцом, когда вы не хотите использовать формулу. Например. вы могли бы определить

isEmpty :: Tree -> Bool
isEmpty Null = True
isEmpty _ = False

sumOfValues2 :: Tree -> Int
sumOfValues2 Null = 0
sumOfValues2 (Node t1 v t2)
    | isEmpty t1 && isEmpty t2 = v
    | isEmpty t1 = v + (sumOfValues2 t2)
    | isEmpty t2 = v + (sumOfValues2 t1)
    | otherwise = v + (sumOfValues2 t1) + (sumOfValues2 t2)

Кстати, вам не нужны все эти случаи, только это:

sumOfValues :: Tree -> Int
sumOfValues Null = 0
sumOfValues (Node t1 v t2) = v + (sumOfValues t1) + (sumOfValues t2)

Null какое-то постоянное значение, как в C или Java. Это не так - это конструктор для типа Tree.

Матчи-спички делают конструкцию в обратном порядке. Вместо того, чтобы предоставить два значения конструктору, и он дает вам значение соответствующего типа, вы предоставляете значение типа конструктору, и оно дает вам составляющие значения, которые составляют тип. Язык знает, какая ветвь дискриминационного объединения использовалась для создания значения, поэтому оно может соответствовать правильному шаблону. Таким образом, нет необходимости в равенстве, потому что это всего лишь конструкторы и переменные - никакие фактические значения не сравниваются (или даже не обязательно оцениваются).

Что касается вашего редактирования о Ints:

Да, Int в основном тип с неприлично большим количеством конструкторов по направлениям-2 | -1 | 0 | 1 | 2 | 3 | 4 …, Это немного волнистые, но это работает на практике.

 Robert Massaioli18 янв. 2011 г., 02:24
Я думаю, что стоит отметить, что класс Int мог бы быть реализован таким образом, но дело в том, что (насколько я понимаю) была сделана небольшая хакерская атака на все числа по соображениям скорости.
 devoured elysium17 янв. 2011 г., 23:45
Отредактировано оригинальное сообщение.
 sepp2k18 янв. 2011 г., 00:36
Ваше редактирование неверно. Если0 и т.д. были конструкторами дляInt типа, они будут иметь типIntнеNum a => a, Также сопоставление с образцом по номерамделает использоватьEq экземпляр рассматриваемого числового типа.
 sepp2k18 янв. 2011 г., 02:44
@ Роберт: И это неправильно. Причина того, чтоInt не реализован таким образом, не имеет ничего общего со скоростью. Причина в том, что еслиInt были реализованы таким образом, вы не могли бы использовать, например,42 как значение типаInteger или жеDouble и, таким образом, весьNum Система будет несуществующей.

шите шаблон с участием конструкторов, то вы получите соответствие шаблонам по конструкторам. Если вы пишете шаблон, включающий в себя буквальные выражения (а буквальные значения с плавающей запятой или целые числа - только это), вы получаете тест на равенство (из класса Eq) с использованием любого перегруженного определения оператора (==), который может предоставить ваш тип.

Так что, если вы перегружаете свой тип данных Fred, который имеет класс Num и имеет конструктор, также называемый Fred, вы можете определить равенство против целых чисел, проверив, равно ли данное целое число 1. Теперь в этом странном сценарии, если я что-то не замечаю, следующие должны работать:

getFred :: Fred -- get a Fred
getFred = Fred -- invoke the Fred constructor

testFred :: Fred -> Bool -- tests if Fred's equality operator considers 1 equal to Fred
testFred 1 = True -- overloaded (==) tests against 1, so should be true
testFred _ = False -- shouldn't happen, then...

isFredOne = testFred $ getFred -- returns True
Решение Вопроса

спользуемые конструкторы. Например, если вы оцениваете

sumOfValues (Node Null 5 (Node Null 10 Null))

это проверяет образцы сверху вниз:

первый,Null, не совпадает, потому что имеет другую структуру

второй,(Node Null v Null), не совпадает, потому что последний компонент,Nullимеет другую структуру, чем(Node Null 10 Null) (сопоставление с образцом происходит рекурсивно)

третий совпадает сv связано с 5 иt2 связан с(Node Null 10 Null).

Eq и оператор ==, который он определяет, является несвязанным механизмом; изготовлениеTree экземплярEq не изменится, как работает сопоставление с образцом.

Я думаю, что ваше мышление здесь немного отсталое: сопоставление с образцом - это самый простой способ использования значения в Haskell; за исключением некоторых основных типов, таких какInt, Eq реализован с использованием сопоставления с образцом, а не наоборот.

Сопоставление образцов и чисел

Оказывается, числовые литералы - это особый случай. Согласно отчету Haskell (ссылка):

Соответствие шаблону числового, символьного или строкового литералаk против стоимостиv успешно, еслиv ==kгде == перегружен в зависимости от типа шаблона.

 devoured elysium17 янв. 2011 г., 23:44
Отредактировано оригинальное сообщение.
 farmer_oak18 янв. 2011 г., 08:40
@ sepp2k: Вы правы, соответствие шаблону с числовыми литералами особенное. Я отредактировал свой ответ, чтобы исправить это.
 sepp2k18 янв. 2011 г., 00:37
Ваше редактирование неверно. Если0 и т.д. были конструкторами для типа Int, они бы имели типIntнеNum a => a, Также сопоставление с образцом на числах действительно используетEq экземпляр рассматриваемого числового типа.

говоря, что сопоставление с образцом является основным для того, что есть в Haskell, а класс типов Eq - нет.

Таким образом, хотя существуют функции, подобные сопоставлению с образцом, которые требуют Eq, они не сопоставляются с образцом и могут быть реализованы поверх сопоставления с образцом.

какой конструктор типов использовался для создания конкретного экземпляра, и это все, что ему нужно для успешного сопоставления с образцом.

 devoured elysium17 янв. 2011 г., 23:44
Отредактировано оригинальное сообщение.

Ваш ответ на вопрос