почему бы не выразить это сигналами транзисторов в процессоре, lol. Эта мантра довольно-таки забавна, интересно откуда она взялась? Реализация не эквивалентна выражению. Выражение предполагает, что кто-то может это без усилий воспринимать(e.g. читать код и без усилий понимать его), это языковое свойство, а язык — это средство общения человека с машиной, некий интерфейс.
Высокоуровневые языки разве не для того существуют, чтобы определять и строить абстракции?
«Дорога, по обеим сторонам которой тянутся канавы,
называется шоссе. Канава — это выкопанное значительным числом рабочих углубление. Копают канавы при помощи кирок.
Книга это множество нарезанных в четвертку
листов бумаги разного формата, напечатанных и собранных вместе,
переплетенных и склеенных клейстером. Клейстер — это клей.»
[a] = 1 + a + a^2 + a^3 + ... = 1 / (1 - a), откуда
[a] * (1 - a) = 1, откуда
[a] = 1 + a * [a]
Ну или более коротким путём:
[a] = 1 + a + a^2 + ... = 1 + a * (1 + a + a^2 + ...) = 1 + a * [a]
Такими манипуляциями можно получить пару альтернативных определений списка:
[a] = (1 + a) + a^2 * (1 + a) + a^4 * (1 + a) + ... = (1 + a) * (1 + a^2 + a^4 + ...) = (1 + a) * [a^2]
[a] = 1 + a * [a] = 1 + a * (1 + a) * [a^2]
Или в хаскеле:
data List a = List (Maybe a) (List (a, a))
data List a = Nil | List a (Maybe a) (List (a, a))
Второе определение обладает интересным преимуществом. Вычисление длины списка — логарифмическая задача. Возможно и конкатенацию так можно сделать дешёвой без дифлистов.
какой нахрен паттерн-матчинг в хаскеле? В виде синтаксической косметики над ветвлением? Какой толк в этом кроме экономии на спичках? Шоб було?
Паттерн-матчинг — это свойство декларативных языков, потомков Планнера и Пролога, где поддерживается бектрекинг на уровне языка, где ты декларируешь факты, а затем задаешь вопросы программе, а она отвечает.
Это не ортоганално. Эти инструменты родились как взаимодополнение друг другу, это основные механизмы декларативных ЯП. К хаскелю же, и прочим ФЯ паттерн-матчинг просто притянут за уши.
Да и невозможен паттерн-матчинг без бектрекинга. Для доказательства «есть такое A что... » в случае неудачи нужно произвести откат и продолжить вычисление.
Для конструкции и деконструкции данных. Без этого Хаскел немыслим.
А в эрланге эт вообще суть философия. Падаем при сфейлишемся ПМ и рестартуем. Код писать легко, нет нужды в контроле состояния. При этом эрланг язык без бэктрейсинга
Следует еще добавить важный момент - практически все подобные рассуждения _конструктивны_. То есть мы не только можем строить хитро каки-ето тимпы и определения, но и автоматически получать ф-и над ними работающими и выполняющие полезные действия.
Всё, что ты сделал, это показал, что функцию [a] -> b можно представить как пару функций (() -> b, a * [a] -> b) и вторую компоненту каррировать: a * [a] -> b ≅ a -> [a] -> b.
Вот и новые подробности. Оказывается, паттерн-матчинг - это не плюшка, а единственный вариант доступа к меченым объединениям и записям? Тогда я уже не могу отнести его к плюсам.
вот ты сказал и я подумал - кажется, да. Но дело в том что понимаешь, это такая плюшка после которой костыли просто не нужны. Как ты предлагаешь обращаться к типу-сумме без сопоставления?
даже в си если ты будешь писать функции доступа, ты будешь вынужден делать этакое сопоставление с образцом (if(item.type == TYPE_ONE)) и никуда от этого не деться. Похоже что это в принципе единственный доступ к типу-сумме.
Как ты предлагаешь обращаться к типу-сумме без сопоставления?
Здесь я определил тип Апельсин-или-яблоко-с-меткой. Пусть у нас переменная Ая имеет такой тип и компилятор про это знает. Вот как это выглядит в реальном лиспа (сокращая до Аиясм).
;; эти две функции и сеттеры для них можно нагенеририровать автоматически
;; и их не будет видно в исходном коде, будет только
;; (Определить-меченное-объединение Аиясм Апельсин Яблоко)
(defun Аиясм-Яблоко (Сие)
(assert (eq (Аиясм-Метка Сие) 'Яблоко))
(the Яблоко (Аиясм-Значение Сие)))
(defun Аиясм-Апельсин (Сие)
(assert (eq (Аиясм-Метка Сие) 'Апельсин))
(the Апельсин (Аиясм-Значение Сие)))
;; А это собственно пример разбора
(defun Превратить-в-число (Ая)
(declare (type Аиясм Ая)
(ecase (Аиясм-Метка Ая)
(Яблоко
(Вес (Аиясм-Яблоко Ая)))
(Апельсин
(Цена (Аиясм-Апельсин Ая))))
Здесь проверка идёт в рантайме и ecase - плохая конструкция, т.к. она не понимает, что речь идёт именно о тегах типа Аиясм, но это можно поменять, сделав специфическую конструкцию, она будет вполне органично смотреться. Избавиться от проверок в рантайме нельзя (т.е. я не знаю как), и тут как раз и есть профит Хаскеля - давай не будем тратить время на этот аспект.
Если перейти к лирике, я пробовал несколько либ паттерн-матчинга для лиспа. Но как-то ни одна не прижилась у меня. Отсюда вывод: для лиспа паттерн-матчинг - лишь инструмент, без него вполне можно обойтись.
Тебе ответная задача: напиши сравнение двух Аиясм на Хаскеле с ПМ, чтобы выдавалась какая-то инфа о месте, где они не совпадают.
паттерн-матчинг это не плюшка и не калач, а банальное отражение того факта, что c^(a + b) = c^a * c^b, т.е. (a+b) -> c ≅ (a -> c, b -> c), т.е. способ записать функцию из sum type как несколько функций по каждому типу из суммы.
Тебе ответная задача: напиши сравнение двух Аиясм на Хаскеле с ПМ, чтобы выдавалась какая-то инфа о месте, где они не совпадают.
Пытаюсь понять задачу. т.е. есть аясм1 и аясм2. И мы хотим сделать
если (аясм1==аясм2)
сказать "они равны"
иначе
(сказать
"первый был яблоко, а второй апельсин"
или
"оба яблоки но вес первого 100г а второго 200г"
в зависимости от ситуации)
но ПМ ведь можно использовать и в выражениях (let,where,case), он не ограничен твоим применением
короче ПМ это удобный способ деконструкции и сравнения данных, мне непонятно чего ТС агрится. он представлен не только в Хаскеле. я бы однозначно выбрал язык с его поддержкой. например в Эрланге благодаря нему удобно разбирать бинарные протоколы http://erlang.org/doc/programming_examples/bit_syntax.html
доступ к полям в сишке это прошлый век, банально неудобно
в общем не уверен верно ли понял задачу, но если верно, то вот, самый «обычный» способ
module Ao where
data Ao = Apple Int | Orange Int
difference :: Ao -> Ao -> String
difference (Apple a) (Apple b) | a == b = "both are apples, weights are equal"
difference (Apple _) (Apple _) | otherwise = "both are apples, but weights are different"
difference (Orange a) (Orange b) | a == b = "both are oranges, weights are equal"
difference (Orange _) (Orange _) | otherwise = "both are oranges, but weights are different"
difference (Apple _) _ = "first is apple, second is orange"
difference _ _ = "first is orange, second is apple"
Ничего не мешает. Это недостаток, я об этом написал. Если хотим добавить поддержку, можно ввести конструкцию, к-рая будет писаться как-то так:
(Просеять-все-теги-меченого-объединения Ая Аиясм
(Апельсин ; внутри этих скобок будет определно (Апельсин Ая)
(Цена (Апельсин Ая))
(Яблоко
(Вес (Яблоко Ая)))
При этом компилятор обругается на упущение какого-то тега (а кстати, это нужно не во всех случаях) и не позволит обратиться к яблоку внутри ветки апельсина и наоборот.
А ведь весь смысл паттерн-матчинга(в изначальном, академическом смысле этого слова, именно в том, чтобы не описывать все случаи явным образом). В хаскеле паттерн-матчинг — это наоборот, получается, инверсия паттерн-матчинга. То есть, то что делает инерпретатор в декларативном языке, хаскелист делает вручную, и называет это «паттерн-матчингом».
data Fruit = Apple | Orange deriving (Show, Eq)
data Ao = Ao Fruit Int
wdiff w1 w2 | w1 == w2 = "weights are equal"
| otherwise = "weights are different"
diff2 (Ao f1 a1) (Ao f2 a2) | f1 == f2 = "both are of type " ++ show f1 ++ ", " ++ wdiff a1 a2
| otherwise = "first is " ++ show f1 ++ ", second is " ++ show f2
data Fruit = Apple | Orange deriving (Show, Eq)
wdiff w1 w2 | w1 == w2 = "weights are equal"
| otherwise = "weights are different"
diff2 (f1, a1) (f2, a2) | f1 == f2 = "both are of type " ++ show f1 ++ ", " ++ wdiff a1 a2
| otherwise = "first is " ++ show f1 ++ ", second is " ++ show f2
То что называют хаскелисты «паттерн матчингом» таковым не является. Это эквивалент ветвлений, на самом деле, сахар над ветвлениями. Некоторое ограниченное подмножество паттерн-матчинга используется, например, в языках баз данных. А в полной мере эта концепция представлена в декларативных языках, таких как Planner и Prolog, и их производных (conniver etc)
Тут надо определится что такое «является». Видимо, все таки надо ориентироваться на те источники, которые эту терминологию ввели в употребление в CS — Хьюитт, Ковальски etc. Если ориентироваться на текущий информационный фон, представленый разного рода бложеками, *мнениями*, *версиями*, то, возможно и не является.
Думал, что проявится такая проблема, как необходимость повтора тегов. Она в первом варианте и была. Но в последующем варианте ты от этого избавился - это годнота.
на самом деле первый вариант хоть и работает, но он не совсем верен, я там наповторял определений где не нужно. правильный первый вариант такой должен быть.
data Ao = Apple Int | Orange Int
difference :: Ao -> Ao -> String
difference (Apple a) (Apple b) | a == b = "both are apples, weights are equal"
| otherwise = "both are apples, but weights are different"
difference (Orange a) (Orange b) | a == b = "both are oranges, weights are equal"
| otherwise = "both are oranges, but weights are different"
difference (Apple _) _ = "first is apple, second is orange"
difference _ _ = "first is orange, second is apple"
Это считается за повторение?
Потом код короче из за того что стало можно сравнивать if(Apple == Orange) и просто конвертировать в строку. В данном варианте этого «чита» нет, чистый паттерн матчинг для фруктов.