Haskell a better way a replacing a character in a string - list

I made this function
replace :: Char -> Char -> [Char] -> [Char]
replace _ _ [] = []
replace a b (c:r)
| a == c = b : replace a b r
| otherwise = c : replace a b r
and was looking for a better way to write it when i found this :
replace :: Char -> Char -> [Char] -> [Char]
replace a b = map $ \c -> if c == a then b else c
There not even the third argument written, and i don't understand the $ and the \c symbols, but it work and I want to know what is happening here

The $ operator applies a function to an argument. We can rewrite your example as
replace :: Char -> Char -> [Char] -> [Char]
replace a b = map (\c -> if c == a then b else c)
Pragmatically, Haskellers often use $ to avoid parentheses. It's rarely used for other reasons.
About the \c -> ...: this is an anonymous function, also called a "lambda". It stands for the function taking c as argument and returning the ... part. In your case, the function takes c and checks if it's equal to a, in which case it returns b, otherwise it returns c. We could rewrite the code without the lambda as follows:
replace :: Char -> Char -> [Char] -> [Char]
replace a b = map myFun
where
myFun :: Char -> Char
myFun = \c -> if c == a then b else c
or, moving the argument c to the left of =, as follows:
replace :: Char -> Char -> [Char] -> [Char]
replace a b = map myFun
where
myFun :: Char -> Char
myFun c = if c == a then b else c
About the "missing third argument": the type Char -> Char -> [Char] -> [Char] can be read in multiple ways:
the type of functions taking one argument (Char) and returning a function (Char -> [Char] -> [Char])
the type of functions taking two arguments (Char and Char) and returning a function ([Char] -> [Char])
the type of functions taking three arguments (Char, Char, and [Char]) and returning a list ([Char])
All these three interpretations are compatible, thanks to currying. Indeed, the "two arguments" function
foo :: A -> B -> B
foo x y = y
and the function
foo :: A -> B -> B
foo x = id -- id is the identity function B -> B
are the same.
In your example, if you want, you can add the missing argument to both sides of = as follows:
replace :: Char -> Char -> [Char] -> [Char]
replace a b xs = map myFun xs
where
myFun :: Char -> Char
myFun c = if c == a then b else c
In this expanded code, you can see that map myFun xs uses map (library function) to apply myFun to all the elements of list xs, and return the list of all the results.
This effectively achieves the substitution you want.
However, without adding the third argument,
replace :: Char -> Char -> [Char] -> [Char]
replace a b = map myFun
where ...
we can still interpret map myFun as transforming the function myFun :: Char -> Char into a function [Char] -> [Char]. The latter is indeed the return type of replace if we interpret that as a "two arguments" function. That is, replace 'a' 'b' is the function [Char] -> [Char] which takes a string and replaces every 'a' in it with a 'b'.

There not even the third argument written. (…)
In Haskell, all functions have only one argument. Indeed Char -> Char -> [Char] -> [Char] is short for Char -> (Char -> ([Char] -> [Char])), it is thus a function that takes a Char and then returns another function. If we apply that function with another Char, it returns a function of type [Char] -> [Char] that will map a list of Chars to a list of Chars, and finally if we call that function with a list of Chars we get a list of Chars.
This thus means that if there are two parameters in the head of the function, that map $ \c -> if c == a then b else c should return a function, and that is the case.
(…) I don't understand the $ (…) symbols.
The ($) :: (a -> b) -> a -> b function is defined as:
infixr 0 $
($) :: (a -> b) -> a -> b
($) f x = f x
it is thus function application. The reason why that is used is because it has a precedence of 0, this thus means that a $ b x for example will be evaluated as a (b x), whereas a b x, will be evaluated as (a b) x. It thus means that the function is equivalent to map (\c -> if c == a then b else c).
I don't understand (…) the \c symbols
That is a lambda expression. It is a function that takes as input a variable c and maps this on the part at the right of the arrow (->). Here it thus means that it maps a Character c to b if c == a; and otherwise it returns c.

Related

What does f: 'a -> b' -> c' -> d' mean in ocaml?

If I have a function f defined as
f: 'a -> 'b -> c' -> d'
Does that mean it takes one argument? Or 3? And then it outputs one argument? How would I use or call such a function?
As Glennsl notes in the comments, it means both.
Very briefly, and by no means comprehensively, from an academic perspective, no function in OCaml takes more than one argument or returns more or less than one value. For instance, a function that takes a single argument and adds 1 to it.
fun x -> x + 1
We can give that function a name in one of two ways:
let inc = fun x -> x + 1
Or:
let inc x = x + 1
Either way, inc has the type int -> int which indicates that it takes an int and returns an int value.
Now, if we want to add two ints, well, functions only take one argument... But functions are first class things, which means a function can create and return another function.
let add =
fun x ->
fun y -> x + y
Now add is a function that takes an argument x and returns a function that takes an argument y and returns the sum of x and y.
We could use a similar method to define a function that adds three ints.
let add3 =
fun a ->
fun b ->
fun c -> a + b + c
The type of add would be int -> int -> int and add3 would have type int -> int -> int -> int.
Of course, OCaml is not purely an academic language, so there is convenience syntax for this.
let add3 a b c = a + b + c
Inferred types
In your question, you ask about a type 'a -> 'b -> 'c -> 'd``. The examples provided work with the concrete type int. OCaml uses type inferencing. The compiler/interpreter looks at the entire program to figure out at compile time what the types should be, without the programmer having to explicitly state them. In the examples I provided, the +operator only works on values of typeint, so the compiler _knows_ incwill have typeint -> int`.
However, if we defined an identity function:
let id x = x
There is nothing her to say what type x should have. In fact, it can be anything. But what can be determined, if that the function will have the same type for argument and return value. Since we can't put a concrete type on that, OCaml uses a placeholder type 'a.
If we created a function to build a tuple from two values:
let make_tuple x y = (x, y)
We get type 'a -> 'b -> 'a * 'b.
In conclusion
So when you ask about:
f: 'a -> 'b -> 'c -> 'd
This is a function f that takes three arguments of types 'a, 'b, and 'c and returns a value of type 'd.

OCaml: Why does `let f : int -> int list -> int list = (::);;` fail?

I would think that OCaml would read
let f : int -> int list -> int list = (::);;
as an instance of partial application, and store the function as f. However, the compiler complains that the function is applied to too few arguments. Any insight into this would be appreciated, thank you.
The value :: in OCaml is a constructor rather than a general function. As such it requires following arguments (in parentheses). You can use it in the (::) form, but it must be followed by two values in parentheses:
# ( :: ) (3, []);;
- : int list = [3]
The same is true of other constructors, like say Some:
# let f : 'a -> 'a option = Some
Error: The constructor Some expects 1 argument(s),
but is applied here to 0 argument(s)
You can of course define your function like this:
let f : int -> int list -> int list = fun a b -> (::) (a, b)
Or this:
let f : int -> int list -> int list = fun a b -> a :: b
Or even like this:
let f : int -> int list -> int list = List.cons
(Other languages, notably Haskell, treat constructors the same as functions. So you can have partially applied constructors, etc. In my opinion this is esthetically superior, i.e., it seems more elegant.)

What is the purpose of an arrow "->" in OCaml

I've been learning OCaml recently and as of now it would seem an arrow is used by the compiler to signify what the next type would be. For instance, int -> int -> <fun> an integer which returns an integer, which returns a function.
However, I was wondering if I can use it natively in OCaml code. In addition, if anyone would happen to know the appropriate name for it. Thank you.
The operator is usually called type arrow where T1 -> T2 represents functions from type T1 to type T2. For instance, the type of + is int -> (int -> int) because it takes two integers and returns another one.
The way -> is defined, a function always takes one argument and returns only one element. A function with multiple parameters can be translated into a sequence of unary functions. We can interpret 1 + 2 as creating a +1 increment function (you can create it by evaluating (+) 1 in the OCaml command line) to the number 2. This technique is called Currying or Partial Evaluation.
Let's have a look at OCaml's output when evaluating a term :
# 1 + 2;;
- : int = 3
# (+) 1 ;;
- : int -> int = <fun>
The term1+2 is of type integer and has a value of 3 and the term (+) 1 is a function from integers to integers. But since the latter is a function, OCaml cannot print a single value. As a placeholder, it just prints <fun>, but the type is left of the =.
You can define your own functions with the fun keyword:
# (fun x -> x ^ "abc");;
- : bytes -> bytes = <fun>
This is the function which appends "abc" to a given string x. Let's take the syntax apart: fun x -> term means that we define a function with argument x and this x can now appear within term. Sometimes we would like to give function names, then we use the let construction:
# let append_abc = (fun x -> x ^ "abc") ;;
val append_abc : bytes -> bytes = <fun>
Because the let f = fun x -> ... is a bit cumbersome, you can also write:
let append_abc x = x ^ "abc" ;;
val append_abc : bytes -> bytes = <fun>
In any case, you can use your new function as follows:
# append_abc "now comes:" ;;
- : bytes = "now comes:abc"
The variable x is replaced by "now comes:" and we obtain the expression:
"now comes:" ^ "abc"
which evaluates to "now comes:abc".
#Charlie Parker asked about the arrow in type declarations. The statement
type 'a pp = Format.formatter -> 'a -> unit
introduces a synonym pp for the type Format.formatter -> 'a -> unit. The rule for the arrow there is the same as above: a function of type 'a pp takes a formatter, a value of arbitrary type 'a and returns () (the only value of unit type)
For example, the following function is of type Format.formatter -> int -> unit (the %d enforces the type variable 'a to become int):
utop # let pp_int fmt x = Format.fprintf fmt "abc %d" x;;
val pp_int : formatter -> int -> unit = <fun>
Unfortunately the toplevel does not infer int pp as a type so we don't immediately notice(*). We can still introduce a new variable with a type annotation that we can see what's going on:
utop # let x : int pp = pp_int ;;
val x : int pp = <fun>
utop # let y : string pp = pp_int ;;
Error: This expression has type formatter -> int -> unit
but an expression was expected of type
string pp = formatter -> string -> unit
Type int is not compatible with type string
The first declaration is fine because the type annotation agrees with the type inferred by OCaml. The second one is in conflict with the inferred type ('a' can not be both int and string at the same time).
Just a remark: type can also be used with records and algebraic data types to create new types (instead of synonyms). But the type arrow keeps its meaning as a function.
(*) Imagine having multiple synonymes, which one should the toplevel show? Therefore synonyms are usually expanded.
The given answer doesn't work for ADTs, GADTs, for that see: In OCaml, a variant declaring its tags with a colon
e.g.
type 'l generic_argument =
| GenArg : ('a, 'l) abstract_argument_type * 'a -> 'l generic_argument

You can find out if a list is a palindrome using (==) <*> reverse. How does it work?

I've tried to go through this using the types, but I'm still having difficulty understanding how it works.
Given:
> :t (==)
(==) :: Eq a => a -> a -> Bool
> :t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
> :t reverse
reverse :: [a] -> [a]
> :t (==) <*> reverse
(==) <*> reverse :: Eq a => [a] -> Bool
Intuitively I can understand that it combines the equality operator with reverse in such a way that it creates a function that checks if a reversed list is equal to the original, but that's really not much more information than what is already pretty obvious.
Could someone break down in more detail the internals of what is actually happening here?
Start with the type of (<*>)
> : t (<*>)
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
Now (->) k is an instance of Applicative, with implementation
instance Applicative ((->) k) where
pure a = \_ -> a
f <*> g = \k -> f k (g k)
In particular, the type of (<*>) specialised to (->) k is
(<*>) :: (k -> a -> b) -> (k -> a) -> (k -> b)
So the application (==) <*> reverse is
(==) <*> reverse = \k -> (==) k (reverse k)
= \k -> k == reverse k
i.e. it checks that a list is equal to its reverse.
Chris Taylor's answer is just right, but another way of looking at it, that I find more intuitive, is this: what the Applicative instance of function types does is this:
"Feed" the same argument value to two functions with the same argument type;
Combine their results with another function.
So basically, if you have f :: t -> a and g:: t -> b, the Applicative instance lets you map functions h :: a -> b -> c over the a and b results, under the assumption that f and g will be fed the same argument.
So think of how you'd write the palindrome test in a non-convoluted way:
palindrome :: Eq a => [a] -> Bool
palindrome xs = xs == reverse xs
xs appears twice on the right hand side of the definition: once as argument to ==, and a second time as argument to reverse. This automatically tells you that there is likely a way to use the (->) t applicative instance to eliminate the duplication. A different, perhaps more intuitive attack on this would be to first rewrite the function to this:
palindrome xs = id xs == reverse xs
...where id x = x is the identity function, which just returns its argument (and is a standard library function). Now you can rewrite that using the standard Applicative idiom (f <$> a0 <*> ... <*> an) to this:
-- Function that feed the same argument value to both `id` and `reverse`,
-- then tests their results with `==`:
palindrome = (==) <$> id <*> reverse
And now we can ask if there is a way to get rid of id in that rewrite. Since <$> is just shorthand for fmap, we can study the Functor instance for (->) t, which is just another way to express function composition:
instance Functor ((->) t) where
-- Mapping `f` over a *function* `g` is just the same as composing `f`
-- on the results of `g`.
fmap f g = f . g
One of the most important properties of function composition is that for any function f:
f . id = f
So applying that to the version of palindrome above, we get:
-- Since `f . id = f` for all `f`, then `(==) <$> id` is just `(==)`:
palindrome = (==) <*> reverse

Get function as parameter in haskell

I can't figure this, I have a type called Enumeration
> type Enumeration a = Int -> [a]
And I need to map over it. I wrote this following function:
> imapE :: (a -> b) -> Enumeration a -> Enumeration b
> imapE f (m fa) = \n -> imapF f fa
where imapF is defined like this:
> imapF :: (a -> b) -> [a] -> [b]
> imapF _ [] = []
> imapF f (x:xs) = f x : imapF f xs
but when I try to load my code I get the following error BinaryTrees.lhs:91:14: Parse error in pattern: m regarding my imapE function.
I am trying to get the first enumeration Enumeration a as the function it is (Int and [a])
You cannot pattern match over a function, but you don't have to do that:
> imapE :: (a -> b) -> Enumeration a -> Enumeration b
> imapE f g = (imapF f) . g
(Well, imapF is just map really).
Without using .:
> imapE :: (a -> b) -> Enumeration a -> Enumeration b
> imapE f g = \n -> imapF f (g n)
A possible solution could be
imapE :: (a -> b) -> Enumeration a -> Enumeration b
imapE = map . map
Indeed, the above is equivalent to
imapE f = map (map f)
where
f :: a -> b
map f :: [a] -> [b]
map (map f) :: (Int -> [a]) -> (Int -> [b])
since both [] and (->) Int are functors.
The main "trick" to this kind of exercises is to think more about the types than the actual values.
This might feel a bit obscure if you're a beginner. Once you'll get more familiar with functors, however, this will become quite natural.
(People very accustomed to this style could even hint to this solution with some cryptic note "functors compose", and leaving you to figure out what's really going on. When that happens, don't give up -- eventually it will make sense ;-))