Я всегда заинтересован в изучении новых языков, факт, который держит меня в напряжении и делает меня (я считаю) лучшим программистом. Мои попытки покорить Хаскелл приходили и уходили - вдвое больше - и я решил, что пришло время попробовать еще раз. 3-й раз это очарование, верно?
Нет. Я перечитываю свои старые заметки ... и разочаровываюсь: - (
Проблема, которая заставила меня потерять веру в прошлый раз, была легкой: перестановки целых чисел.
то есть из списка целых чисел, в список списков - список их перестановок:
[int] -> [[int]]
На самом деле это общая проблема, поэтому замена 'int' выше на 'a' все равно будет применяться.
Из моих заметок:
Сначала я пишу код самостоятельно, мне это удается. Ура!
Я отправляю свое решение моему хорошему другу - гуру Хаскелла, оно обычно помогает учиться у гуру - и он посылает мне это, как мне говорят, "выражает истинную силу языка, использование общих средств кодировать ваши потребности ". Все для этого, я недавно выпил kool-aid, поехали:
permute :: [a] -> [[a]]
permute = foldr (concatMap.ins) [[]]
where ins x [] = [[x]]
ins x (y:ys) = (x:y:ys):[ y:res | res <- ins x ys]
Хм.
Давайте разберем это:
bash$ cat b.hs
ins x [] = [[x]]
ins x (y:ys) = (x:y:ys):[ y:res | res <- ins x ys]
bash$ ghci
Prelude> :load b.hs
[1 of 1] Compiling Main ( b.hs, interpreted )
Ok, modules loaded: Main.
*Main> ins 1 [2,3]
[[1,2,3],[2,1,3],[2,3,1]]
Хорошо, пока все хорошо. Мне потребовалась минута, чтобы понять вторую строку «ins», но хорошо:
Он помещает 1-й аргумент во все возможные позиции в списке. Круто.
Теперь, чтобы понять foldr и concatMap. в "Реальном мире Хаскелла" ТОЧКА была объяснена ...
(f . g) x
... как еще один синтаксис для ...
f (g x)
И в коде, который послал гуру, DOT использовался из Foldr, с функцией «ins» как «свертывание» фальца:
*Main> let g=concatMap . ins
*Main> g 1 [[2,3]]
[[1,2,3],[2,1,3],[2,3,1]]
ОК, так как я хочу понять, как DOT используется гуру, я пробую эквивалентное выражение в соответствии с определением DOT, (f. G) x = f (g x) ...
*Main> concatMap (ins 1 [[2,3]])
<interactive>:1:11:
Couldn't match expected type `a -> [b]'
against inferred type `[[[t]]]'
In the first argument of `concatMap', namely `(ins 1 [[2, 3]])'
In the expression: concatMap (ins 1 [[2, 3]])
In the definition of `it': it = concatMap (ins 1 [[2, 3]])
Что!?! Зачем?
Хорошо, я проверяю сигнатуру concatMap и нахожу, что ей нужны лямбда и список, но это
просто человеческое мышление; как справится GHC? Согласно определению DOT выше ...
(f.g)x = f(g x),
... то, что я сделал, было действительным, по замене:
(concatMap . ins) x y = concatMap (ins x y)
царапающая головка ...
*Main> concatMap (ins 1) [[2,3]]
[[1,2,3],[2,1,3],[2,3,1]]
Итак ... Объяснение DOT было очевидно
слишком упрощенно ... DOT должен быть достаточно умным, чтобы понять
что мы на самом деле хотели, чтобы «ины» вырвались и «съели» первое
аргумент - таким образом становясь функцией, которая хочет работать только с [t]
(и «чередуйте» их с «1» во всех возможных положениях).
Но где это было указано? Как GHC знал, что делать это, когда мы вызывали:
*Main> (concatMap . ins) 1 [[2,3]]
[[1,2,3],[2,1,3],[2,3,1]]
Подпись "ins" как-то передавала эту политику "съесть мой первый аргумент"?
*Main> :info ins
ins :: t -> [t] -> [[t]] -- Defined at b.hs:1:0-2
Я не вижу ничего особенного - «ins» - это функция, которая принимает «t»,
список 't', и приступает к созданию списка со всеми "interspersals". Ничего о "съешь свой первый аргумент и убери его".
Так что ... я сбит с толку. Я понимаю (после часа просмотра кода!) Что происходит, но ... Бог всемогущий ... Возможно, GHC пытается выяснить, сколько аргументов он может "снять"?
let's try with no argument "curried" into "ins",
oh gosh, boom,
let's try with one argument "curried" into "ins",
yep, works,
that must be it, proceed)
Опять - yikes ...
И поскольку я всегда сравниваю языки, которые я изучаю, с тем, что я уже знаю, как будет выглядеть «ins» в Python?
a=[2,3]
print [a[:x]+[1]+a[x:] for x in xrange(len(a)+1)]
[[1, 2, 3], [2, 1, 3], [2, 3, 1]]
Если честно, теперь ... что проще?
Я имею в виду, я знаю, что я новичок в Haskell, но я чувствую себя идиотом ... Глядя на 4 строки кода в течение часа и заканчивая тем, что компилятор ... пробует различные интерпретации, пока не найдет что-то, что «щелкает»?
Цитата из смертоносного оружия: "Я слишком стар для этого" ...