I can't understand why the following function works with 2 arguments even if we declare it with one param:
let rec removeFromList e = function
h :: t -> if h=e then h
else h :: removeFromList e t
| _ -> [];;
removeFromList 1 [1;2;3];;
You're declaring it with two parameters. The syntax:
let f = function ...
can be seen as a shortcut for
let f x = match x with
So, your definition is actually:
let rec removeFromList e lst = match lst with
h :: t -> if h=e then h else h :: removeFromList e
Related
I am currently taking a class in Haskell and am having a bit of trouble understanding how functions are passed as parameters. For this assignment, we were tasked with creating a program that would evaluate expressions. To reduce boiler plating, I wanted to abstract the function by creating a helper function that would take in an operator as an input and return the result
Main Function:
eval :: EDict -> Expr -> Maybe Double
eval _ (Val x) = Just x
eval d (Var i) = find d i
eval d (Add x y) = evalOp d (+) x y
eval d (Mul x y) = evalOp d (*) x y
eval d (Sub x y) = evalOp d (-) x y
Helper Function:
evalOp:: EDict -> ((Num a) => a -> a -> a) -> Expr -> Expr -> Maybe Double
evalOp d op x y =
let r = eval d x
s = eval d y
in case (r, s) of
(Just m, Just n) -> Just (m `op` n)
_ -> Nothing
Other definitions
data Expr
= Val Double
| Add Expr Expr
| Mul Expr Expr
| Sub Expr Expr
| Dvd Expr Expr
| Var Id
| Def Id Expr Expr
deriving (Eq, Show)
type Dict k d = [(k,d)]
define :: Dict k d -> k -> d -> Dict k d
define d s v = (s,v):d
find :: Eq k => Dict k d -> k -> Maybe d
find [] _ = Nothing
find ( (s,v) : ds ) name | name == s = Just v
| otherwise = find ds name
type EDict = Dict String Double
I looked into how +,-, and * are to be passed into other functions and found that these operators are defined by the following definition:
ghci> :t (*)
(*) :: (Num a) => a -> a -> a
However, when I run my code I get the following compilation error:
Illegal polymorphic or qualified type: Num a => a -> a -> a
Perhaps you intended to use RankNTypes or Rank2Types
In the type signature for ‘evalOp’:
evalOp :: EDict
-> ((Num a) => a -> a -> a) -> Expr -> Expr -> Maybe Double
I am not really sure why this is happening as I gave my function the proper parameters as defined by Haskell. Any help would be greatly appreciated as I am still very new to the language.
Right now, your Expr data type is constrained to Double-valued expressions, so there is no need to deal with polymorphism.
evalOp:: EDict -> (Double -> Double -> Double) -> Expr -> Expr -> Maybe Double
evalOp d op x y =
let r = eval d x
s = eval d y
in case (r, s) of
(Just m, Just n) -> Just (m `op` n)
_ -> Nothing
(+) :: Num a => a -> a -> a is a valid argument for evalOp, because its type can be "restricted" to Double -> Double -> Double.
> let f :: Double -> Double -> Double; f = (+)
> f 3 5
8.0
If your expression type were parameterized, then you would put a Num a constraint on your functions (not just on the arguments that involve a, because you want the same a throughout the function).
data Expr a
= Val a
| Add (Expr a) (Expr a)
| Mul (Expr a) (Expr a)
| Sub (Expr a) (Expr a)
| Dvd (Expr a) (Expr a)
| Var Id
| Def Id (Expr a) (Expr a)
deriving (Eq, Show)
type EDict a = Dict String a
evalOp:: Num a => EDict a -> (a -> a -> a) -> Expr a -> Expr a -> Maybe a
evalOp d op x y =
let r = eval d x
s = eval d y
in case (r, s) of
(Just m, Just n) -> Just (m `op` n)
_ -> Nothing
eval :: Num a => EDict a -> Expr a -> Maybe a
eval _ (Val x) = Just x
eval d (Var i) = find d i
eval d (Add x y) = evalOp d (+) x y
eval d (Mul x y) = evalOp d (*) x y
eval d (Sub x y) = evalOp d (-) x y
The error is telling you that you cannot nest a type qualifier inside one of the types in your function chain. Instead, put all of the qualifiers at the beginning of the type signature:
evalOp:: (Num a) => EDict -> (a -> a -> a) -> Expr -> Expr -> Maybe Double
See Haskell - Illegal Polymorphic type? for a more thorough discussion.
module Dfs = struct
let rec dfslsts g paths final =
let l = PrimePath.removeDuplicates (PrimePath.extendPaths g paths)
in
let f elem =
if (List.mem "%d" (List.flatten final) = false) then (dfslsts g ["%d"] (List.flatten l)::final)
else final
in
List.iter f (Graph.nodes g)
end
Error: This expression has type string but an expression was expected of type int list
This error occurred when I called dfslsts function, which is recursive, inside the if condition.
The function dfslsts returns a list of lists.
If I try to replace the complex expression in if statement to
if (List.mem "%d" (List.flatten final) = false) then "%d"
else "%d"
then I get
Error: This expression has type 'a -> string
but an expression was expected of type 'a -> unit
Type string is not compatible with type unit
at List.iter line.
How do I solve this problem and are we allowed to call a recursive function inside the if expression.
This is the definition of my graph type:
module Graph = struct
exception NodeNotFound of int
type graph = {
nodes : int list;
edges : (int * int) list;
}
let makeGraph () =
{
nodes = [];
edges = [];
}
let rec isNodeOf g n = List.mem n g.nodes
let nodes g = g.nodes
let edges g = g.edges
let addNode g n =
let nodes = n::g.nodes and edges = g.edges in
{
nodes;
edges;
}
let addEdge g (n1, n2) =
if ((isNodeOf g n1) = false) then
raise (NodeNotFound n1)
else if ((isNodeOf g n2) = false) then
raise (NodeNotFound n2)
else
let nodes = g.nodes
and edges = (n1, n2) :: g.edges in
{
nodes;
edges;
}
let nextNodes g n =
let rec findSuccessors edges n =
match edges with
[] -> []
| (n1, n2) :: t ->
if n1 = n then n2::findSuccessors t n
else findSuccessors t n
in
findSuccessors g.edges n
let rec lastNode path =
match path with
[] -> raise (NodeNotFound 0)
| n :: [] -> n
| _ :: t -> lastNode t
end
module Paths = struct
let extendPath g path =
let n = (Graph.lastNode path) in
let nextNodes = Graph.nextNodes g n in
let rec loop path nodes =
match nodes with
[] -> []
| h :: t -> (List.append path [h]) :: (loop path t)
in
loop path nextNodes
let rec extendPaths g paths =
match paths with
[] -> []
| h :: t -> List.append (extendPath g h) (extendPaths g t)
(* Given a list lst, return a new list with all duplicate entries removed *)
let rec removeDuplicates lst =
match lst with
[]
| _ :: [] -> lst
| h :: t ->
let trimmed = removeDuplicates t in
if List.mem h trimmed then trimmed
else h :: trimmed
end
Any expression can be a recursive function call. There are no limitations like that. Your problem is that some types don't match.
I don't see any ints in this code, so I'm wondering where the compiler sees the requirement for an int list. It would help to see the type definition for your graphs.
As a side comment, you almost certainly have a precedence problem with this code:
dfslsts g ["%d"] (List.flatten l)::final
The function call to dfslsts has higher precedence that the list cons operator ::, so this is parsed as:
(dfslsts g ["%d"] (List.flatten l)) :: final
You probably need to parenthesize like this:
dfslsts g ["%d"] ((List.flatten l) :: final)
I have a function with the following signature:
val func : a -> b -> c -> d -> e -> f -> unit
and sometimes it raises exceptions. I want to change the control flow so that it looks like this:
val funcw : a -> b -> c -> d -> e -> f -> [ `Error of string | `Ok of unit ]
The way I tried wrapping it is ugly: make another function, funcw, that takes the same amount of arguments, applies func to them, and does try/with. But there must be a better way than that. Thoughts?
You can make f a parameter of the wrapper function. That's a little more general.
let w6 f a b c d e g =
try `Ok (f a b c d e g) with e -> `Error (Printexc.to_string e)
A wrapped version of func is then (w6 func)
This wrapper works for curried functions of 6 arguments, like your func. You can't really define a single wrapper for all the different numbers of arguments (as they have different types), but you can define a family of wrappers for different numbers of arguments like this:
let w1 f x = try `Ok (f x) with e -> `Error (Printexc.to_string e)
let ws f x y =
match f x with
| `Ok f' -> (try `Ok (f' y) with e -> `Error (Printexc.to_string e))
| `Error _ as err -> err
let w2 f = ws (w1 f)
let w3 f x = ws (w2 f x)
let w4 f x y = ws (w3 f x y)
let w5 f x y z = ws (w4 f x y z)
let w6 f x y z w = ws (w5 f x y z w)
There might be a tidier scheme but this seems pretty good.
I have to write the function try_finalyze f g y x of type : ('a -> 'b) -> ('b -> 'c) -> 'c -> 'a -> 'c
knowing that:
1. if an exception is raised by f x the returned value has to be y
2. if f x doesn't raise any exception we have to return the result of g applied on f x
exception E
let try_finalyze f g y x = try g (f x) with E -> y;;
val try_finalyze : ('a -> 'b) -> ('b -> 'c) -> 'c -> 'a -> 'c = <fun>
1.Is it right how I treated the problem?
2.In this context what will do the following function:
fun f -> try_finalyze f (fun x-> Some x) None
I don't see the role of a function like (fun x-> Some x)
The answer to your first question is - not really. According to your specification function should catch any exception, not only your exception E. Maybe I'm misreading, but it will be better use the following definition:
let try_finalize f g y x = try g (f x) with exn -> y
As for the second part of the question, there're several ways in OCaml to signal an error. The two most common are:
Raise an exception
Return a value of an option type
The former variant is syntactically lighter, the later doesn't allow a caller to ignore the error condition. Sometimes you need to switch from one variant to an another. Suppose you have a function that raises an exception, and you would like to create a function with the same behavior, but returning an option value. Let's give it a name:
let with_option f = try_finalize f (fun x-> Some x) None
Then we can, for example, convert a List.hd to a function that returns an option type, depending on whether the list is empty or not:
let head x = with_option List.hd x
This function will have type 'a list -> 'a option, compare it with List.hd type 'a list -> 'a, the former will not allow to ignore the empty list case. When applied to an empty list, it will return a None value:
# head [];;
- : 'a option = None
If you write
let try_finalize f g y x = try g (f x) with _ -> y
Your function will return y if f doesn't raise an error but g does, which is not what you said you want.
To ensure that you catch only errors from f you should put f x alone in the try block:
let try_finalize f g y x =
let z = try Some (f x) with _ -> None in
match z with
| Some z -> g z
| None -> y
Exceptions may be considered bad style in a purely functional code, that's why you may want to transform a function that may raise an exception such as List.assoc : 'a -> ('a * 'b) list -> 'b into a function that does the same thing but returns an option.
That's what
let with_option f = try_finalize f (fun x-> Some x) None
does.
If I understand the problem statement correctly, I think I would do this :
let try_finalize f g y x =
try
let v = f x in g v
with _ -> y
As for question 2, suppose you have a function f that takes a value of type v and computes a result of type r. This :
fun f -> try_finalize f (fun x-> Some x) None
returns a function that tries to apply f. If it succeeds (i.e. no exception is thrown), it returns Some r. Otherwise, it returns None. Basically, it transforms a function that may throw an exception into a function that will not throw anything. The new function returns a r option instead of a r.
Maybe like this but the function doesn't have anymore the required type
let try_finalyze f g y x = match f x with
|E -> y
| _ -> g (f x) ;;
I have this function:
let rec som a b acc =
if a > b then acc else
som (a+1) b (acc+(comb b a));;
And what I am trying to do is to save acc value in a hashtable, so my first try was:
let rec som a b acc =
if a > b then acc else
som (a+1) b (acc+(comb b a)) Hashtbl.add a acc;;
but it does not work... How can I save the values?
This is skeleton, you can try to add you code into it to get what you want. Maybe it will be helpful.
module Key = struct
type t=int
let compare: t->t->int = fun a b -> (* return -1 if a<b, 0 if a=b,and 1 if a>b *)
let equal = (=)
end
module H=Hashtbl.Make(Key)
let som =
let h = H.create () in
let rec f a b acc =
try H.find h acc
with Not_found ->
let ans = (* your evaluation code *) in
H.add h acc ans;
ans
in
f
First, let's take a look at the signature of Hashtbl.add
('a, 'b) Hashtbl.t -> 'a -> 'b -> unit = <fun>
The first argument of the function is an hash table, then you need to create one. To do it, write let h_table = Hashtbl.create 123456;;. And to put it in context your add instruction become HashTbl.add h_table a acc
Next, you can't call this function at the same level of the recursive call. Indeed the function som take three arguments and you will face the following error message, It is applied to too many arguments ....
And as you want to trace the value of acc you need to put it before the recursive call. Doing this can lead you to face some difficulty, then I've added below a hint.
let _ = Printf.printf "a\n" in
let _ = Printf.printf "b\n" in
(1+2)
;;
a
b
- : int = 3