Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a function as a parameter and returning a function - Haskell

I have a graph of Function f(n) where it returns

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 

and I wanted to write a function that will represent a graph with one List with pairs:

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' [] [] = []

And thats what I did here. Passing a list [5,2,-4,1,9,8,9] returns

*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)]

and here is the function that does oposite:

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

where passing the graph [(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]

Question:

What I dont understand is how to write something like this:

type Function = (Nat0 -> Z) 

function_to_list :: Function -> List

or

list_to_function :: List -> Function

or the same for graph

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

I have read Higher order functions on this link but I cant seem to grasp how this actually works.

I suppose in function_to_list I would have to pass a function that has this notation (Nat0 -> Z)(which is actually Int -> Int ) and it should return a List with [Z] (which is [Int] ). But how do I do that? That is like passing same function to itself?

Even more confusing is the list_to_function what should here be the result?

If somebody can explain me higher order Functions on some of my examples I would really be thankful!

EDIT:

To be more clear here is what I want to achieve:

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

As I showed above if I pass a list to list_to_graph it return a graph and graph_to_list does oposite

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

its the same that I want to do with the other two functions. If I apply function_to_list to list_to_function as function_to_list returns a List and list_to_function accepts a List it should return a function that will take a elements out of the list and apply it to Function which will return a Z.

What I figured out by now:

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

As the answer bellow suggested.

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

What I want to do is to make this function :: Function in my list_to_function

like image 886
cheshire Avatar asked Dec 01 '18 18:12

cheshire


People also ask

Can you pass in a function as a parameter?

Function Call When calling a function with a function parameter, the value passed must be a pointer to a function. Use the function's name (without parentheses) for this: func(print); would call func , passing the print function to it.

What is a curried function Haskell?

From HaskellWiki. Currying is the process of transforming a function that takes multiple arguments in a tuple as its argument, into a function that takes just a single argument and returns another function which accepts further arguments, one by one, that the original function would receive in the rest of that tuple.

What is flip in Haskell?

Description: it evaluates the function flipping the order of arguments. Related: Example 1. Input: flip (/) 1 2.


2 Answers

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

This function exists and is called zip.

Note: zip also works for lists of different length, ignoring the the extra bit of the longer list, whereas yours fails if both are not of the same length

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

You could write this function as,

graph_to_list = map snd

or

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

or

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

Regarding this,

What I dont understand is how to write something like this:

type Function = (Nat0 -> Z) 

function_to_list :: Function -> List

If I understand you correctly you would like to be able to build the "image of f", that is a list all values f x for all x in the domain of f. Something that in theory could look like,

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

However in general there is no way to know the domain of a given function (much less a way to traverse it). Same goes for the translation of a function into a graph. To implement such "transformations" you have to provide as argument both your function f :: A -> B and a list xs :: A with the points of its domain which you want to consider.

like image 172
Jorge Adriano Avatar answered Oct 19 '22 02:10

Jorge Adriano


So you are trying to get

list_to_function :: List -> Function

correct? Let's do Graph instead, it will get closer to the essence. Let's start writing it.

graph_to_function gph = _ -- something of type Function

So we want to construct something of type Function, that is, Nat0 -> Z. The most boring way to do that is with a lambda:

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

Great, now we have a Graph called gph and a Nat0 called n, and we want to make a Z. Here we can just search the list for n. There are a few ways to do this, here's one:

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

I put ++ [0] on the end just in case the list comprehension ends up empty, that is, we didn't find n in the domain of the graph. Done!

Fun fact, functions in Haskell are curried by default, so

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

are equivalent. That is, graph_to_function is really just the same thing as a two-argument function. So we can move the n over to the left side of the definition:

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

It's looks a bit weird to have only one argument in the signature are two arguments in the equation, but it is something that you see in the wild, once you get used to it.

Hope this helps!

like image 21
luqui Avatar answered Oct 19 '22 01:10

luqui