Как читать этот функциональный код - PullRequest
0 голосов
/ 17 мая 2018

Не удается прочитать (интерпретировать) этот функциональный код Миранды.

g = (foldr (+) 0) . (foldr ((:) . ((#) . (:[]))) [])

Я знаю, что он делает

  • Рассчитать размер списка, взяв длину с помощью #
  • Создание списка из одного элемента, содержащего вышеуказанную длину исходного списка ввода
  • Свертывание нового списка с использованием foldr в одно целое число с операцией +0 для каждого элемента

Однако меня смущают скобки, и я не вижу, куда вводится список ввода. Что делает самый правый конструктор []?

Кроме того, почему этот код работает толькочерез функцию g, но если я вызываю ее напрямую, выдается ошибка?

Ответы [ 2 ]

0 голосов
/ 17 мая 2018

Я не слишком хорошо знаю Миранду, но на основе Хаскелла (я полагаю, что различия между ними здесь будут незначительными, поскольку только # является унарным оператором для длины списка, являющимся единственным полусущественным и с || - это синтаксис комментария): . - это состав функции:

(p . q) x = p (q x)
  || also can be written as:
p . q = \x -> p (q x)

Композиция функций является ассоциативной операцией, поэтому p . (q . r) = (p . q) . r = p . q . r.

Используя эту информацию, мы можем расширить ее с помощью определения .:

g      = (foldr (+) 0) . (foldr ((:) . ((#) . (:[]))) [])       || Original definition
g list = foldr (+) 0 (foldr ((:) . ((#) . (:[]))) [] list)
g list = foldr (+) 0 (foldr (\x -> (:) (((#) . (:[])) x)) [] list)
g list = foldr (+) 0 (foldr (\x -> (:) ((\y -> (#) ((:[]) y)) x)) [] list)

Это можно исправить еще немного:

g list = foldr (+) 0 (foldr (\x -> (:) ((\y -> (#)(y:[])) x)) [] list) || More conventional operator syntax for the innermost `:`
g list = foldr (+) 0 (foldr (\x -> (:) ((#)(x:[]))) [] list)           || Innermost lambda was applied to x. Substitute y for x.
g list = foldr (+) 0 (foldr (\x -> (:) ((#)([x]))) [] list)            || Apply innermost `:`
g list = foldr (+) 0 (foldr (\x -> (:) #[x])) [] list)                 || Remove unnecessary parentheses
g list = foldr (+) 0 (foldr (\x acc -> (:) (#[x]) acc) [] list)        || Explicitly write implicit argument. This particular step is called eta-expansion
g list = foldr (+) 0 (foldr (\x acc -> (:) 1 acc) [] list)             || #[x] is always 1, no matter what x is
g list = foldr (+) 0 (foldr (\x acc -> 1 : acc) [] list)               || More conventional syntax for `:`

Также обратите внимание, что foldr не применяется +0 к каждому элементу, как вы указали в вопросе. foldr op z (a:b:c:[]) становится op a (op b (op c z))) (a:b:c:[] - это еще один способ написать [a,b,c]). Я всегда думал, что эта диаграмма полезна, чтобы понять, что:

foldr diagram

Кроме того, наиболее вероятной причиной возникновения ошибки при непосредственном вызове является то, что p . q x означает , а не так же, как (p . q) x.

0 голосов
/ 17 мая 2018

Короче говоря, g - это функция, которая возвращает длину списка.

Давайте разберем функцию на несколько частей.

|| returns 1 for any input.
||   return_one "hoobar" = 1
return_one :: * -> num
return_one = (#) . (:[]) 

|| ignore first argument, insert 1 to the second argument.
||   insert_one "hoobar" [4,5,6] = [1,4,5,6]
insert_one :: *->[num]->[num]
insert_one = (:) . return_one

|| sum of list.
||   sum_list [7,8,9] = 24
sum_list :: [num] -> num 
sum_list = foldr (+) 0

|| generate list of 1 which as the same length of original list. 
||   change_one ["apple","banana"] = [1,1]
change_one :: [*] -> [num]
change_one = foldr insert_one []

|| return the length of the list.
||   g ["apple","banana"] = 2
g :: [*] -> num
g = sum_list . change_one

Я бы объяснил некоторые запутанные функции.

return_one

(:[]) - это функция, которая создает список из одного элемента, а (#) возвращает длину.Строго говоря, (:[]) - это (:), который принимает [] в качестве первого аргумента.

, следовательно, (:[]) "hoobar" = "hoobar":[] = ["hoobar"], а применение (#) возвращает 1.

change_one

Он начинается с пустого списка [] и пересекает список с добавлением 1 вперед.

foldr insert_one [] ["apple","banana"]
= foldr insert_one [1] ["apple"]
= foldr insert_one [1,1] []
...