Передача функции в качестве параметра и возвращение функции - Haskell - PullRequest
0 голосов
/ 01 декабря 2018

У меня есть график функции f(n), где он возвращает

5  if n = 0 
2  if n = 1 
-4 if n = 2 
1  if n = 3 
9  if n = 4 
8  if n = 5 
9  if n = 6 
0  otherwise 

, и я хотел написать функцию, которая будет представлять граф с одним списком с парами:

type Nat0 = Int 
type Z = Int
type List = [Z] 
type Graph = [(Nat0,Z)] 

list_to_graph :: List -> Graph
list_to_graph x = list_to_graph' ([0..(length x)-1 ]) (x)

list_to_graph' :: [Int] -> List -> Graph
list_to_graph' (x:xs) (y:ys) = [(x, y)] ++ list_to_graph' (xs) (ys)
list_to_graph' [] [] = []

И это то, что я сделал здесь.Передача списка [5,2,-4,1,9,8,9] возвращает

*Main> list_to_graph [5,2,-4,1,9,8,9]
[(0,5),(1,2),(2,-4),(3,1),(4,9),(5,8),(6,9)]

, и вот функция, которая делает противоположной:

graph_to_list :: Graph -> List
graph_to_list (x:xs) = [snd (x)] ++ graph_to_list(xs)
graph_to_list []= [] 

, где проходит граф [(0,5),(1,2),(2,-4),(3,1),(4,9),(5,8),(6,9)]

*Main> graph_to_list [(0,5),(1,2),(2,-4),(3,1),(4,9),(5,8),(6,9)]
[5,2,-4,1,9,8,9]

Вопрос:

Я не понимаю, как написать что-то вроде этого:

type Function = (Nat0 -> Z) 

function_to_list :: Function -> List

или

list_to_function :: List -> Function

или то же для графа

function_to_graph :: Function -> Graph
graph_to_function :: Graph -> Function

Я прочитал Функции высшего порядка по этой ссылке, но я не могу понять, как это на самом деле работает.

Полагаю, в function_to_list я бычтобы передать функцию с этой нотацией (Nat0 -> Z) (которая на самом деле Int -> Int) и она должна вернуть List с [Z] (что [Int]).Но как мне это сделать?Это похоже на передачу той же самой функции себе?

Еще более запутанным является list_to_function каков здесь должен быть результат?

Если кто-то может объяснить мне функции более высокого порядка на некоторых из моих примеров, я был бы действительно благодарен!

РЕДАКТИРОВАТЬ:

Чтобы быть более ясным, вот чего я хочу достичь:

(list_to_graph . graph_to_list) = λ x. x
(graph_to_list . list_to_graph) = λ x. x

Как я показал выше, если я передам список list_to_graphон возвращает график, и graph_to_list делает oposite

(list_to_function . function_to_list) = λ x. x
(function_to_list . list_to_function) = λ x. x

таким же, как я хочу сделать с двумя другими функциями.Если я применяю function_to_list к list_to_function, так как function_to_list возвращает List и list_to_function принимает List, он должен вернуть функцию, которая вычеркнет элементы из списка и применит ее к Function, которыйвернет Z.

Что я понял к настоящему моменту:

function_to_list :: Function-> List
function_to_list f = [f(x) | x <- [0..6]]

function :: Function
function n
         | n == 0 = 5
         | n == 1 = 2 
         | n == 2 = (-4)
         | n == 3 = 1
         | n == 4 = 9
         | n == 5 = 8
         | n == 6 = 9
         | otherwise = 0

Как подсказывает ответ ниже.

*Main> function_to_list function 
[5,2,-4,1,9,8,9]

Что я хочу сделать, это сделать это function :: Function вмой list_to_function

Ответы [ 2 ]

0 голосов
/ 02 декабря 2018

Итак, вы пытаетесь получить

list_to_function :: List -> Function

правильно?Давайте вместо этого сделаем Graph, это приблизится к сути.Давайте начнем писать.

graph_to_function gph = _ -- something of type Function

Итак, мы хотим построить что-то типа Function, то есть Nat0 -> Z.Самый скучный способ сделать это с помощью лямбды:

graph_to_function gph = \n -> _ -- something of type Z

Отлично, теперь у нас есть Graph с именем gph и Nat0 с именем n, и мы хотим сделатьZ.Здесь мы можем просто найти в списке n.Есть несколько способов сделать это, вот один:

graph_to_function gph = \n -> head ([ y | (x,y) <- gph, x == n ] ++ [0])

Я ставлю ++ [0] в конце на случай, если понимание списка окажется пустым, то есть мы не нашли nв области графа.Готово!

Интересный факт, функции в Haskell по умолчанию карри, поэтому

f x y z = ...
f = \x -> \y -> \z -> ...

эквивалентны.То есть graph_to_function - это то же самое, что и функция с двумя аргументами.Таким образом, мы можем переместить n в левую часть определения:

graph_to_function :: Graph -> Function
graph_to_function gph n = head ([ y | (x,y) <- gph, x == n ] ++ [0])

Несколько странно иметь только один аргумент в сигнатуре - это два аргумента в уравнении, но это нечточто вы видите в дикой природе, как только вы привыкнете к этому.

Надеюсь, это поможет!

0 голосов
/ 01 декабря 2018
list_to_graph' :: [Int] -> List -> Graph
list_to_graph' (x:xs) (y:ys) = [(x, y)] ++ list_to_graph' (xs) (ys)
list_to_graph' [] [] = []

Эта функция существует и называется zip.

Примечание: zip также работает для списков различной длины, игнорируя дополнительный бит более длинного списка, в то время как ваш не работает, если оба не имеют одинаковую длину

graph_to_list :: Graph -> List
graph_to_list (x:xs) = [snd (x)] ++ graph_to_list(xs)
graph_to_list []= []

Вы можете написать эту функцию как

graph_to_list = map snd

или

graph_to_list xs = [snd x | x <- xs]

или

graph_to_list xs = [a | (a,b) <- xs]

Что касается этого,

Я не понимаю, как написать что-то вроде этого:

type Function = (Nat0 -> Z) 

function_to_list :: Function -> List

ЕслиЯ правильно вас понимаю, вы хотели бы иметь возможность создать «образ f», то есть список всех значений f x для всех x в домене f.То, что в теории могло бы выглядеть,

[f(x) | x <- DOMAIN f]

Однако в общем случае нет способа узнать область данной функции (а тем более способ ее обойти).То же самое касается перевода функции в граф.Для реализации таких «преобразований» вы должны предоставить в качестве аргумента как вашу функцию f :: A -> B, так и список xs :: A с точками своего домена, которые вы хотите рассмотреть.

...