Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.145.93.210] |
|
Страницы: (4) [1] 2 3 ... Последняя » все ( Перейти к последнему сообщению ) |
Сообщ.
#1
,
|
|
|
Здрасте!
начал изучать Haskell вот пытаюсь перевести на JS код с Haskell но тока в функциональном стиле JS nouns = ["frog","raven","ribbit"] adjectives = ["lazy","angry","tiny","happy","shy"] mixin nouns adjectives = [adj ++ " " ++ noun | adj <– adjectives, noun <– nouns] Выхлоп [ "lazy frog","angry frog","tiny frog","happy frog","shy frog", "lazy raven","angry raven","tiny raven","happy raven","shy raven", "lazy ribbit","angry ribbit","tiny ribbit","happy ribbit","shy ribbit" ] Пробую через Array,reduce, пока стена |
Сообщ.
#2
,
|
|
|
Сам порешал
function mixin(nouns, adjs) { return nouns.reduce((a, noun) => { const v = adjs.map(adj => { return adj + ' ' + noun; }); return [...a, ...v]; }, []); } На хаскелле как то более проще думать такие задачи, лямбда исчисление рулит! Haskell: mixin nouns adjs = [adj ++ " " ++ noun | adj <– adjs, noun <– nouns] Так изменил в более функциональный стиль JS, но все равно не так очевидно как на Хаскеле const mixin = (nouns, adjs) => nouns.reduce((a, noun) => [...a, ...adjs.map(adj => adj + ' ' + noun)], []); |
Сообщ.
#3
,
|
|
|
Продолжаю изучать удивительный Haskell!
Еще одна задачка на поиск прямоугольных треугольников, дано три списка с числами от 1 до 10 например, надо найти все совпадения прямоугольных треугольников. На хаскеле изи! aa =[1..10] bb = [1..10] cc = [1..10] triples aa bb cc = [(a,b,c) | a <- aa, b <- bb, c <- cc, a^2 + b^2 == c^2] Выхлоп [(4,3,5),(3,4,5),(8,6,10),(6,8,10)] Как теперь это на JS написать? Добавлено Переключил моск с функционального на императивный режим Оказывается тут идет тупой перебор по трем циклам const aa = [1,2,3,4,5,6,7,8,9,10]; const bb = [1,2,3,4,5,6,7,8,9,10]; const cc = [1,2,3,4,5,6,7,8,9,10]; function triples(aa, bb, cc) { var v=[]; aa.forEach(a => { bb.forEach(b => { cc.forEach(c => { if ((a*a + b*b) === c*c) { v.push([a,b,c]); } }); }); }); return v; } |
Сообщ.
#4
,
|
|
|
Одно замечание по коду, в Хаскеле все функции автоматически каррируются
на JS это будет выглядеть так // Каррированная версия triples function triples(aa) { return bb => { return cc => { var v = []; aa.forEach(a => { bb.forEach(b => { cc.forEach(c => { if ((a*a + b*b) === c*c) { v.push([a,b,c]); } }); }); }); return v; }; }; } triples(aa)(bb)(cc); зачем Хаскель это делает? да хз я еще не дошел до этого... вроде бы это связано с его реализацией, а именно лямбда функциями в данном коде на JS это делать не обязательно |
Сообщ.
#5
,
|
|
|
Разобрался зачем
Для того чтобы юзать их в функциях высшего порядка, например const result = [[1,2,3,4,5],[6,7,8,9,10]].map(triples(aa)(bb)); console.log(result); // [[[ 3, 4, 5 ]], [[ 6, 8, 10 ]]] ну а на Haskell все проще map (triples aa bb) [[1..5],[6..10]] // [[(3,4,5)],[(6,8,10)]] Кто не понял объясняю, каррированная функция передается функции высшего порядка путем частичного применения Добавлено Очередной вопрос, вот на Haskell код так называемой быстрой сортировки quicksort [] = [] quicksort (x : xs) = quicksort [a | a <- xs, a <= x] ++ [x] ++ quicksort [a | a <- xs, a > x] как его переделать на JS |
Сообщ.
#6
,
|
|
|
Вот вам функционально-подобная попытка на JS приблизится к великому Хаскеллу
function quicksort(array) { if (array.length === 0) return []; const origin = [...array]; const elem0 = origin.pop(); const left = origin.filter(elem => elem < elem0); const right = origin.filter(elem => elem >= elem0); return [...quicksort(left), elem0, ...quicksort(right)]; } var nums = [10,2,5,3,1,6,7,4,2,3,4,8,9]; var sortedNums = quicksort(nums); console.log(nuts); // [ 10, 2, 5, 3, 1, 6, 7, 4, 2, 3, 4, 8, 9 ] console.log(sortedNums); // [ 1, 2, 2, 3, 3, 4, 4, 5, 6, 7, 8, 9, 10 ] И все равно императивный стиль JS присутствует |
Сообщ.
#7
,
|
|
|
Для евангелистов reduce коим являюсь сам , вот более оптимизированая версия за счет одного цикла, вместо двух в случае с filter:
function quicksort(array) { if (array.length === 0) return []; const origin = [...array]; const elem0 = origin.pop(); var res = origin.reduce((aa, elem) => ( (elem < elem0) ? [[...aa[0], elem], aa[1]] : [aa[0], [...aa[1], elem]] ), [[],[]]); return [...quicksort(res[0]), elem0, ...quicksort(res[1])]; } Цикла? Да-да не удивляйтесь! В JS все равно надо переключаться в императивный режим |
Сообщ.
#8
,
|
|
|
Продолжаю переносить задачки из Хаскель на JS
вот исходная задачка на удаление определенного числа элементов из списка с использованием рекусии: drop 0 xs = xs drop _ [] = [] drop n (x:xs) = drop (n-1) xs а вот та же но через foldl (это аналог reduce в JS) drop 0 xs = xs drop _ [] = [] drop n xs = foldl (\xs _ -> tail xs) xs [1..n] С рекурсией на JS не было проблем function drop(n, array) { if (n === 0) return array; if (array.length == 0) return []; array.shift(); return drop(n-1, array); } drop(1, [1,2,3]) // [2,3] а вот как сделать тоже но через reduce? Небольшая поправочка в Хаскелле все данные иммутабельны, а у меня тут исходный массив array меняется, что не в Хаскел-стиле! Правим: function drop(n, array) { const origin = [...array]; if (n === 0) return origin; if (array.length == 0) return []; origin.shift(); return drop(n-1, origin); } |
Сообщ.
#9
,
|
|
|
ВСЕ ПРОСТО!! я забыл что в JS можно изменять состояние, это ж не Хаскель
Мде сложно переключаться с функционального на императивный режим, надо тернироваться Вот решение, получается еще проще чем в Хаскелле function drop(n, array) { if (n === 0) return array; if (array.length == 0) return []; return array.reduce((accum, elem) => (n-- > 0) ? accum : [...accum, elem], //<--- ВОТ ТУТ ИЗМЕНЯЕМ n. []); } или через filter еще проще function drop(n, array) { if (n === 0) return array; if (array.length == 0) return []; return array.filter(() => (n-- <= 0)); } да и начальные условия тут тоже можно опустить function drop(n, array) { return array.filter(() => (n-- <= 0)); } Хотя я погорячился сказав что проще Хаскеля не проще! куда ж еще проще? drop n xs = foldl (\(_:xs) _ -> xs) xs [1..n] Да в JS уже есть функция удаления splice, но моя цель перевести с Haskell на JS в функциональном стиле, хотя в предыдущих вариантах был применен полу императивный стиль, а не фунциональный и решение в Haskell стиле требует еще покумекать ну т.е. сделать без мутации переменной n. |
Сообщ.
#10
,
|
|
|
Так так так... ща рожу... а не показалось
|
Сообщ.
#11
,
|
|
|
.... иииии! родил зверюшку!
function drop(n, array) { const v = [...Array(n)].map((_,n) => n + 1); return v.reduce(xs => { xs.shift(); return xs; }, [...array]); } Объясняю что тут происходит. Я не сразу допедрил как можно это решить без мутации n! Сила императивного стиля моск реально морозит но после долгих насилований себя я прозрел! если внимательно посмотреть на код Хаскелля видно что он просто производит свертку по числовому списку, а не по целевому списку! Вот где фокус то был! Ну а дальше дело техники, генерирую массив чисел от 1 до n поскольку в JS нет встроенного генератора массива как в Хаскелле и далее делаю свертку хотя это на самом деле не свертка, а простая мутация исходного массива путем выкидывания лишних элементов Все тоже можно было сделать тупо в цикле, но мне хотелось приблизить код к Хаскел-стилю, ну те. к функциональному стилю Немного видоизменил код чтобы максимально приблизится к Haskell: const genN = n => [...Array(n).map((_, n) => n + 1)]; const drop = (n, xs) => genN(n).reduce(xs => (xs.shift(), xs), [...xs]); Вроде бы уже похоже на функциональный стиль |
Сообщ.
#12
,
|
|
|
Реализация drop через свертку исходного списка
drop n xs = fst $ foldr f z xs where f x (xs, m) | m > 0 = (x:xs, m-1) f _ (xs, _) = (xs,0) z = ([], m) m = length xs - n получилось длиннее, но более понятно теперь надо перевести на JS OK. будем думать. ПС. в последнее время я стал адептом краткой нотации |
Сообщ.
#13
,
|
|
|
Готово! Максимально приближенный Хаскель-стиль
const drop = (n, xs) => ( xs.reduceRight(({xs, m}, x) => ( (m > 0) ? (xs.unshift(x), {xs, m: m-1}) : {xs, m:0} ), {xs:[], m: xs.length - n}).xs ); Нравится мне эта шифрограмма! |
Сообщ.
#14
,
|
|
|
Продолжаем, на очереди dropWhile, его суть отсечение элементов списка по условию. Пока условие истина элементы выкидываются, как только условие ложно все остальные элементы включаются в список:
dropWhile p xs = fst $ foldl f z xs where f (xs, b) x | b && p x = (xs, True) f (xs, _) x = (xs ++ [x], False) z = ([], True) dropWhile (>3) [4,1,2,3,4,5] // [1,2,3,4,5] p - предикат, xs - список Надо преложить на JS. Думаем! Хотя пока думаю один я |
Сообщ.
#15
,
|
|
|
Решил по аналогии с drop!
const dropWhile = (p, xs) => ( xs.reduce(({xs, b}, x) => (b && p(x)) ? {xs, b:true} : {xs:[...xs, x], b:false}, {xs:[], b:true}).xs ); dropWhile(x => x > 3, [4,1,2,3,4,5] // [1,2,3,4,5] немного были затыки с анонимной функцией, а так изи Переменную b в JS можно не передавать в акумуляторном объекте, его можно мутировать в замыкании, тут я просто перенес один в один решение в Хаскелл-стиле где нельзя менять значения переменных Например вот как будет в императивном стиле JS const dropWhile = (p, xs) => { var b = true; //исходное состояние return xs.reduce((xs, x) => (b && p(x)) ? xs : (b = false, [...xs, x]), // ^^ изменяем состояние []) }; как видите код в немного сократился, за счет выкидывания b из аккумуляторного объекта и замены его простым массивом. Первые впечатления от Хаскелла в основном положительные Функциональный стиль, строгая типизация и т.д все классно, но если сравнивать с моим кодингом на JS, на Хаскелл сложнее отлаживать хотя он и строго типизирован, но вот мессажи об ошибках, которые возникаю при компиляции, вгоняют меня в ступор, например hof.hs:81:15: error: * Couldn't match expected type `[a1]' with actual type `([a1], Bool)' * In the first argument of `(++)', namely `xs' In the expression: xs ++ [x] In the expression: (xs ++ [x], False) * Relevant bindings include x :: a1 (bound at hof.hs:81:10) xs :: ([a1], Bool) (bound at hof.hs:81:7) f :: ([a1], Bool) -> a1 -> ([a1], Bool) (bound at hof.hs:80:5) да на JS было много ошибок в рантайме, но хз я их изи правил и находил, чего не скажу пока про Хаскелл думаю если научусь их читать, то ваще будет шоколадно Рекомендую ли я Haskell к изучению новичкам в программировании? Скорее нет, чем да а вот тем кто уже мастер императивном программинге, то велком в Хаскелл найдете много интересного! И мозоль в мозге первое время будет большая Эт я еще монады не трогал и не прогал GUI, БД и тп, знающие прогеры ну те кто круче меня пугают меня ими |