p
являє собою (поліморфний клас класу) функцію, що приймає перестановку як список Int
s, і вкладений список, що представляє багатовимірний масив Int
s.
Зателефонуйте як p [2,1] [[10,20,30],[40,50,60]]
, однак, якщо типова помилка типу не вдається, вам, можливо, доведеться додати анотацію типу, наприклад :: [[Int]]
(вкладеного належним чином), надаючи тип результату.
import Data.List
class P a where p::[Int]->[a]->[a]
instance P Int where p _=id
instance P a=>P[a]where p(x:r)m|n<-p r<$>m,y:z<-sort r=last$n:[p(x:z)<$>transpose n|x>y]
Спробуйте в Інтернеті!
Проблеми з гольфом із вкладеними масивами довільної глибини в Хаскеллі трохи незручні, оскільки статичний набір тексту, як правило, перешкоджає. Хоча списки Haskell (з точно таким же синтаксисом, як і в описі виклику) можуть вкладатись чудово, списки різної глибини вкладення несумісні. Крім того, для стандартних функцій розбору Haskell потрібно знати тип значення, яке ви намагаєтеся розібрати.
Як результат, видається неминучим необхідність програми включати декларації, що стосуються типу, які є відносно багатослівними. Щодо гольф-частини, я зупинився на визначенні класу типу P
, такого, який p
може бути поліморфним щодо типу масиву.
Тим часом, тестовий джгут TIO показує спосіб подолати проблему розбору.
Як це працює
Підсумовуючи суть цього алгоритму: Він виконує сортування бульбашок у списку перестановок, переносячи сусідні розміри при заміні відповідних індексів перестановки.
Як зазначено в class P a
декларації, у будь-якому випадку p
береться два аргументи, перестановка (завжди типу [Int]
) та масив.
- Перестановку можна навести у формі опису виклику, хоча спосіб роботи алгоритму вибір індексів довільний, за винятком їх відносного порядку. (Отже, робота на основі 0 і 1).
- База
instance P Int
обробляє масиви розмірності 1, які p
просто повертаються незмінними, оскільки один вимір може бути відображений лише для себе.
- Інший
instance P a => P [a]
визначається рекурсивно, викликаючи p
розмірність n підматрив, щоб визначити його для розмірності n + 1 масивів.
p(x:r)m
Перший p r
рекурсивно викликає кожен елемент m
, даючи масив результатів, n
в якому всі розміри, крім першого, перестановлені правильно відносно один одного.
- Інша перестановка, яку потрібно виконати
n
, задається x:y:z = x:sort r
.
- Якщо
x<y
тоді перший вимір n
розміщений вже правильно, n
він просто повертається.
- Якщо
x>y
, тоді перший і другий вимір n
потрібно замінити, що робиться за допомогою transpose
функції. Нарешті p(x:z)
, застосовується рекурсивно до кожного елемента результату, забезпечуючи перенесення вихідного першого виміру у потрібне положення.
exec
(збереження двох байтів) , оскільки це твердження в Python 2.