This question already has an answer here:
how do you read the ramda docs?
(1 answer)
Closed 1 year ago.
Could someone explain how to understand this notation:
((a, b) → a) → a → [b] → a
See: https://ramdajs.com/docs/#reduce
((a, b) → a) → a → [b] → a
^^^^^^^^^^^^ ^ ^^^ ^
1 2 3 4
This is a function that takes three arguments (1) (2) (3) and returns a value of type a (4):
The 1st arg is a function that takes two arguments (maybe of the same type) and returns a value of the same type as the first argument.
The 2nd argument is a value of type a
The 3rd argument is a list of values of type b
reduce( (acc, x) => acc + x.length, 0, ["foo", "bar", "baz"]); //=> 9
// ^^^ ^ ^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^ ^
// a b a a [b] a
// ((a -> b) -> a ) -> a -> [b] -> a
In this case a stands for the number type and b stands for the string type.
I believe its Hindley-Milner notation: https://drboolean.gitbooks.io/mostly-adequate-guide-old/content/ch7.html
Related
let rec fold_inorder f acc t =
match t with
| Leaf -> acc
| Node (l, n, r) -> f (fold_inorder f acc l) (f n (fold_inorder f acc r))
I'm trying to print the infold of a tree as following :
fold_inorder (fun acc x -> acc # [x]) [] (Node (Node (Leaf,1,Leaf), 2, Node (Leaf,3,Leaf))) = [1;2;3]
I'm getting an error saying my [x] is
This expression has type 'a list
but an expression was expected of type 'a
The type variable 'a occurs inside 'a list
I'm really not sure what to do from here. Can anyone nudge me in the right direction?
In your definition of fold_inorder, what type do you expect f to have?
If I look at this call:
f n (fold_inorder f acc r)
it appears that the first parameter of f is a new value from a tree node and the second parameter is an accumulated value.
But in your test call you define f like this:
(fun acc x -> ...)
This suggests that the first parameter is the accumulated value and the second parameter is a new value from a tree node.
> S.reduce(S.flip(S.K),[],S.Left([1,2]))
[]
> S.reduce(S.flip(S.K),[],S.Right([1,2]))
[ 1, 2 ]
I was trying to understand sanctuary and its working can anybody explain the above outcomes in detail
In my understanding S.reduce takes a mapping function and uses the input array which should be of type either and reduces it
But why its empty array in first case and same array in second case
Let's start with a more familiar example: using S.reduce on an array.
> S.reduce (acc => s => acc + s) ('initial:') (['foo', 'bar', 'baz'])
'initial:foobarbaz'
Now, let's specialize the type of S.reduce to explain the behaviour above.
S.reduce :: Foldable f => (b -> a -> b) -> b -> f a -> b
-- replace ‘Foldable f => f’ with ‘Array’ --
S.reduce :: (b -> a -> b) -> b -> Array a -> b
Next, let's specialize the type of S.reduce to see how it will operate on Either values.
S.reduce :: Foldable f => (b -> a -> b) -> b -> f a -> b
-- replace ‘Foldable f => f’ with ‘Either x’ --
S.reduce :: (b -> a -> b) -> b -> Either x a -> b
What can we do when given S.Left ('foo') as the Either x a? We have an x ('foo') but no a. Because we don't have an a we cannot make use of the b -> a -> b function. Thus, the only b we can possibly return is the initial value.
> S.reduce (acc => s => acc + s) ('initial:') (S.Left ('foo'))
'initial:'
What can we do when given S.Right ('bar') as the Either x a? We have an a, which we could feed to the b -> a -> b function along with the initial value to produce another value of type b.
> S.reduce (acc => s => acc + s) ('initial:') (S.Right ('bar'))
'initial:bar'
If S.reduce were to return 'initial:' or 'initial:bar:bar:bar' in the case above it would still be conforming to the type signature, but the fantasy-land/reduce implementation for Sanctuary's Either type applies the function exactly once when given a Right.
I am a student of functional programming, sorry if my question sounds weird--I am trying to wrap my mind around the given type signatures for functions and how they are implemented.
Looking at the signature for ap (Substitution)
https://gist.github.com/Avaq/1f0636ec5c8d6aed2e45
(a → b → c) → (a → b) → a → c
Is given here as
const S = f => g => x => f(x)(g(x));
Which I think I understand. f is a function that takes two parameters, a and b and returns c. g is a function that takes a and returns b. So g(a) returns b and therefore f(a)(b) can be written as f(a)(g(a)), which returns c.
g(a) is the substitute for b ?
Ok now I'm looking at a different implementation that still makes sense:
https://github.com/sanctuary-js/sanctuary-type-classes/tree/v7.1.1#ap--applyf--fa-bfa---fb
ap(Identity(Math.sqrt), Identity(64))
The type signature
(f (a -> b), f a) -> f b
Seem similar to
(a → b → c) → (a → b) → a → c
Re-writing the second using a = f, b = a, and c = b I get
(f -> a -> b) -> (f -> a) -> f -> b
Presuming that ap takes two parameters, where in the first f could be some functor that contains a function a -> b and in the second f some functor that contains a returning a functor that substitutes the first functor's function with the end point b given then functor containing a.
Okay, stepping back, these two things looks vastly different and I can't wrap my mind around how they are somehow saying the same thing.
const S = f => g => x => f(x)(g(x))
ap(Identity(Math.sqrt), Identity(64))
From my understanding, ap(F(g),F(a)) can be express as F(a).map(g) which, again, I still have a hard time equating to const S = f => g => x => f(x)(g(x)). Perhaps I'm misunderstanding something.
...maybe my misunderstanding has to do with the expression of ap and how that correlates to f => g => x => f(x)(g(x)) because I can see how they both express the same signature but I don't see them as the same thing.
Anyone who can lend some cognitive assistance here, I would greatly appreciate it
ap is the name for a transformation that behaves the same way on a large number of container types known as Applicative Functors. One such container type is the Function: it can be treated as a container of its return value.
The S combinator you found in my gist comes from the untyped Lambda Calculus and is a transformation of a Function specifically. It happens to also be a valid implementation of Applicative Functor for Function, and it happens to be the implementation of choice for both Ramda and Sanctuary. This is why you can use ap as S.
To gain an understanding of how ap is S, let's have a look at the signature for ap:
Apply f => (f (a -> b), f a) -> f b
And let's get rid of the comma by currying the function. This should make the next steps a little easier to follow:
Apply f => f (a -> b) -> f a -> f b
The Apply f part shows that, where ever we see f a, we can use an Applicative Functor container that contains a. Let's specialise this signature for the Function container, by replacing f with (Function x). x is the input to the function, and what follows is the output.
(Function x) (a -> b) -> (Function x) a -> (Function x) b
This reads as: Given a Function from x to a Function from a to b, and a Function from x to a, returns a Function from x to b.
We can remove the brackets around Function x, because of the way constructor associativity works:
Function x (a -> b) -> Function x a -> Function x b
And another way to write Function a b is using the arrow notation: (a -> b), so in the next step we do just that:
(x -> (a -> b)) -> (x -> a) -> (x -> b)
And finally we can get rid of the additional brackets again, and find that it's our S combinator:
(x -> a -> b) -> (x -> a) -> x -> b
(a -> b -> c) -> (a -> b) -> a -> c
First of all, I think there is no easy explanation of why the applicative functor for the function type in untyped lambda calculus is called substitution. AFAIK, Schönfinkel originally called this combinator fusing or amalgamation function.
In order to specialize the general applicative functor type (f (a -> b), f a) -> f b (uncurried form), we need to know what the parameterized type variable f exactly represents in the context of the function type.
As every functor applicative functors are parameterized over a single type. The function type constructor, however, needs two types - one for the argument and another for the return value. For functions to be an instance of (applicative) functors, we must therefore ignore the type of the return value. Consequently, f represents (a -> ), ie. the function type itself and the type of its argument. The correct notation for the partially applied function type constructor is actually prefix (->) a, so let's stick to this.
Next, I'm gonna rewrite the general applicative type in curried form and substitute f with (->) r. I use another letter to delimit the type parameter of the applicative from other type variables:
(f (a -> b), f a) -> f b
f (a -> b) -> f a -> f b // curried form
// substitution
(->) r (a -> b) -> (->) r a -> (->) r b // prefix notation
(r -> a -> b) -> (r -> a) -> (r -> b) // infix notation
// omit unnecessary parenthesis
(r -> a -> b) -> (r -> a) -> r -> b
This is exactly the type of the S combinator.
Learning OCaml from here.
I want to verify if I have understood how this snippet of OCaml code works
List.fold_left (fun acc x -> acc + x) 0 [ 1; 2; 3; 4 ]
I have an intuition that this is an equivalent to the reduce function in Python. Specifically, I think it is equivalent to
reduce(lambda x, y: x + y, [1, 2, 3])
The anonymous function is taking two parameters - acc and x and returns a single value acc + x. I understand that initially, the first argument acc will be 0 but how does it know that the second argument has to be the first element of the list?
What I think is happening is that fold_left provides the two arguments to the anonymous function and then recursively calls itself with new arguments until the list becomes empty.
To confirm this I saw this.
When I define a function like let inc x = x + 1 I get something like val inc : int -> int = <fun> but in this case the signature is : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a = <fun>
What is 'a and how should I interpret this function signature so that List.fold_right f [a1; ...; an] b becomes f a1 (f a2 (... (f an b) ...))?
You are asking many questions.
I'm pretty sure that Python reduce is a fold, so your intuition is probably right.
You ask "how does it know that the second argument has to be the first element of the list?" Unfortunately, I don't think this is a well formed question. There's no "it" that knows anything. Most likely the answer is given by the definition of fold_left. It knows what to do because somebody wrote the code that way :-)
Here is the definition of fold_left from the standard library:
let rec fold_left f accu l =
match l with
[] -> accu
| a::l -> fold_left f (f accu a) l
In some sense, this should answer all your questions.
The type 'a in the type of fold_left is the type of the accumulator. The point is that you can use any type you want for the accumulator. This is why the fold is so powerful. As long as it matches the values accepted and returned by the folded function, it can be anything you want.
If I remember correctly, reduce is a simpler version of fold, which takes the first element of the list as starting element. I'd define it this way:
let reduce f = function
| x::xs -> fold_left f x xs
| [] -> failwith "can't call reduce on empty lists!"
If you enter it in OCaml, it will display its type:
val reduce : ('a -> 'a -> 'a) -> 'a list -> 'a
You can contrast it with fold_left's type:
('b -> 'a -> 'b) -> 'b -> 'a list -> 'b
The type variables 'a and 'b here mean that they can stand for any type. In your example, both 'a and 'b become int. If we insert the types, fold_left has the signature:
(int -> int -> int) -> int -> int list -> int
That's what we expected: + is a function which takes two ints and returns a new one, 0 is an int and the [1;2;3;4;] is a list of ints. The case that fold_left has two type variables and reduce only has one already gives a hint that it is more general. To see why we can look at the definition of reduce. Since the starting element of the fold is an element of the list, the types 'a' and 'b must be the same. That's fine for summing up elements, but say, we'd like to construct an abstract syntax tree for our summation. We define a type for this:
type exp = Plus of exp * exp | Number of int
Then we can call:
fold_left (fun x y -> Plus (x, (Number y))) (Number 0) [1; 2; 3; 4]
Which results in the expression:
Plus (Plus (Plus (Plus (Number 0, Number 1), Number 2), Number 3), Number 4)
A benefit of this tree is that you can nicely see what is applied first (0 and 1) - in case of addition this is not a problem, since it is associative (this means a+(b+c) = (a+b)+c) which is not the case for subtraction (compare e.g. 5-(3-2) and (5-3)-2).
If you want to do something similar with reduce, you will notice that OCaml complains about type errors:
reduce (fun x y -> Plus (x, (Number y))) [1; 2; 3; 4] ;;
Error: This expression has type exp but an expression was expected of type
int
In this case, we can wrap each integer as an expression in our input list, then the types agree. Since we already have Numbers, we don't need to add the Number constructor to y:
let wrapped = map (fun x -> Number x) [1; 2; 3; 4] in
reduce (fun x y -> Plus (x, y)) wrapped
Again, we have the same result, but we needed an additional function call to map. In the case of fold_left, this is not necessary.
P.S.: You might have noticed that OCaml gives the type of fold_left as ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a. I guess you will quickly realize that the name of the type variables doesn't play a role. To make it easier to compare, I switched the names such that the function is always applied to a list of 'a.
A little late, but the comparison between OCaml's folds and Python's reduce may be easier if you incorporate reduce's initializer argument.
Summing a list of ints in OCaml using a fold:
let sum = List.fold_left (+) 0 [1; 2; 3]
And using reduce in Python.
from functools import reduce
sum = reduce(int.__add__, [1, 2, 3], 0)
Here you can see the order of arguments is a bit different, but they're all there.
Python feels it's less likely you'll need the initializer, so leaves it at the end as an optional argument as a convenience. OCaml features the list as the last argument also as a convenience, as partial application makes it easy to write something like a sum function.
let sum = List.fold_left (+) 0
Rather than:
let sum lst = List.fold_left (+) 0 lst
I am new to Ocaml and want help with recursive function defined on a recursive data type. I have defined a data type as follows
type 'a slist = S of 'a sexp list
and
'a sexp = Symbol of 'a | L of 'a slist
The function(subst) I'm writing checks for a symbol a in the defined slist and substitutes it by b. For ex subst 1 10 S[ 1; 4; S[L[3; 1;]; 3];] returns S[10; 4; S[L[S[3; 10;]]; 3;]
. My code is as follows
let rec subst a b sl = match sl with
S s -> match s with
[] -> []
| p :: q -> match p with
Symbol sym -> if sym = a then S[b] :: (**subst** a b S[q]) else
S[p] :: (subst a b S[q])
L l -> (subst a b l) :: (subst a b S[q])
| L lis -> subst a b lis;;
I am getting the error :
This function is applied to too many arguments; Maybe you forgot a ';'
Please help
Your type can be defined in a simpler way, you don't need slist:
type 'a sexp = Symbol of 'a | L of 'a sexp list
Your problem is that subst a b S[q] is read as subst a b S [q], that is the function subst applied to 4 arguments. You must write subst a b (S[q]) instead.