Применение и каррирование функций Haskell

Я всегда заинтересован в изучении новых языков, факт, который держит меня в тонусе и делает меня (я верю) лучшим программистом. Мои попытки завоевать Haskell приходят и уходят - уже дважды - и я решил, что пора попробовать еще раз. В третий раз прелесть, верно?

Нет. Я перечитываю свои старые заметки ... и разочаровываюсь: - (

Проблема, которая заставила меня потерять веру в прошлый раз, была простой: перестановки целых чисел. то есть от списка целых чисел к списку списков - списку их перестановок:

[int] -> [[int]]

На самом деле это общая проблема, поэтому замена 'int' выше на 'a' все равно применима.

примечания:

Сначала я кодирую это самостоятельно, мне это удается. Ура!

Я отправляю свое решение своему хорошему другу - гуру Haskell, обычно это помогает учиться у гуру - и он отправляет мне это, что, как мне сказали, «выражает истинную силу языка, использование общие возможности для кодирования ваших потребностей ". Все ради этого, я недавно выпил 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", но нормально: Он помещает первый аргумент во все возможные позиции в списке. Круто.

Теперь давайте разберемся с foldr и concatMap. в "Real world Haskell" DOT была объяснена ...

(f . g) x

... как просто еще один синтаксис для ...

f (g x) 

И в коде, который прислал гуру, DOT использовалась из фолдера с "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 (gx) ...

*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', и переходит к созданию списка со всеми «перемежающимися знаками». Ничего о том, чтобы «съесть свой первый аргумент и убрать его».

Итак ... Я сбит с толку. Я понимаю (после часа разглядывания кода!), Что происходит, но ... Боже всемогущий ... Может, 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)

Опять-таки - ох .. .

И поскольку я всегда сравниваю языки, которые изучаю, с тем, что я уже знаю, как "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 строки кода в течение часа и заканчивая предполагая, что компилятор ... пробует различные интерпретации, пока не находит что-то, что "щелкает"?

Цитата из "Смертельного оружия": " Можно ли поставить галочку в настройках проекта, чтобы внести это изменение?

17
задан Mick 7 October 2010 в 17:18
поделиться