Это тесно связано с вашим другим вопросом о Haskell и быстрой сортировке. Я думаю, вам, вероятно, нужно прочитать хотя бы введение книги о Haskell. Звучит так, как будто вы еще не поняли ключевой момент, а именно то, что он запрещает вам изменять значения существующих переменных.
Обмен (как он понимается и используется в C++) по своей природе связан с изменением существующих значений. Это значит, что мы можем использовать имя для ссылки на контейнер и заменять этот контейнер совершенно другим содержимым, а также настраивать эту операцию так, чтобы она была быстрой (и без исключений) для определенных контейнеров, что позволяет нам реализовать подход «изменить и опубликовать». (крайне важно для написания безопасного от исключений кода или попытки написать код без блокировки).
Вы можете написать общий обмен на Haskell, но он, вероятно, будет принимать пару значений и возвращать новую пару, содержащую те же значения с перевернутыми позициями, или что-то в этом роде. На самом деле это не одно и то же, и не то же самое использование. Нет никакого смысла пытаться специализировать его для карты, копаясь внутри этой карты и меняя местами ее отдельные переменные-члены, потому что вам просто не разрешено делать подобные вещи в Haskell (вы можете сделать специализацию, но не модификация переменных).
Предположим, мы хотим «измерить» список в Haskell:
measure :: [a] -> Integer
Это объявление типа. Это означает, что функция measure
принимает список чего угодно (a
является параметром универсального типа, поскольку начинается с буквы нижнего регистра) и возвращает целое число. Так что это работает для списка любого типа элемента - это то, что можно было бы назвать шаблоном функции в C++ или полиморфной функцией в Haskell (не то же самое, что полиморфный класс в C++).
Теперь мы можем определить это, предоставив специализации для каждого интересного случая:
measure [] = 0
то есть измерьте пустой список, и вы получите ноль.
Вот очень общее определение, которое охватывает все остальные случаи:
measure (h:r) = 1 + measure r
Бит в скобках на LHS — это шаблон. Это значит: возьми список, оторви голову и назови его h, оставшуюся часть назови r. Затем эти имена являются параметрами, которые мы можем использовать. Это будет соответствовать любому списку, в котором есть хотя бы один элемент.
Если вы пробовали метапрограммирование шаблонов в C++, все это будет для вас старым, потому что оно включает в себя точно такой же стиль - рекурсия для выполнения циклов, специализация для завершения рекурсии. За исключением того, что в Haskell это работает во время выполнения (специализация функции для определенных значений или шаблонов значений).
person
Daniel Earwicker
schedule
18.12.2008
area(triangle_type t) {return t.val*t.val/2;}
иarea(square_type t) { return t.val*t.val;}
. моя глупая догадка для функционального языка заключалась бы в том, чтоarea()
вarea(triangle(double))
иarea(square(double))
должны быть специализированными. - person kirill_igum   schedule 11.09.2013data Polygon x = Square x | Triangle x x | Rectangle x x
, а функцияarea :: Polygon -> x
может быть определена как:area (Square s) = s*s
,area (Triangle h b) = h * b/2
иarea(Rectangle l w) = l * w
. - person recursion.ninja   schedule 20.01.2014data Zero; data Succ a
, чтобы вы могли затем определить вектор какdata Vector len = ...
и иметь функцию, которая работает только с векторами размером триf :: Vector (Succ (Succ (Succ Z))) -> ...
. Если вы используете GHC, вы можете делать то же самое, что и в C++ (т. е. использовать целочисленные литералы), используя литералы уровня типа. - person Frerich Raabe   schedule 03.08.2017