I have basically completed my homework, as I only needed a certain amount of working test examples. My only issue is I cannot figure out why this does not work, and I would like to know for my sanity.
let list_helper (x: 'a -> bool) head = if (x head) then true else false
let take_while (x: 'a -> bool) lst =
let rec take_while_helper x lst acc = match lst with
| [] -> []
| h::t -> if list_helper x h then take_while_helper x t (h::acc) else acc in take_while_helper x lst []
take_while (fun _ -> true) [1; 2; 3] should evaluate to [1; 2; 3]. This one does not work.
take_while ((=) "a") ["a"; "a"; "b"; "a"] should evaluate to ["a"; "a"]. Works as expected.
take_while (fun _ -> false) ["say"; "anything"] should evaluate to []. Works as expected.
The last two test cases work, but the first one does not. I made another similar function, and again it does not work. It seems my function does not handle integers well, and I do not know why. I would like to know why it is not behaving correctly, as I though through it logically and it seems like it should work. Maybe I'm missing something about integers and lists.
You also have to return the accumulator in the case of an empty list. And you have to reverse the result, since you add the elements to the accumulator in the wrong order.
So your function could look like
let take_while (x: 'a -> bool) lst =
let rec take_while_helper lst acc = match lst with
| [] -> acc
| h::t -> if x h then (take_while_helper t (h::acc)) else acc
in List.rev (take_while_helper lst [])
Related
let rec isolate (l:'a list) =
match l with
| [] -> []
| x::xs ->
if memberof(x,xs)
then remove (x,l)
else isolate xs
I've already created functions memberof and remove, the only problem is that when line 6 remove(x,l) executes it doesn't continue with isolate(xs) for continued search through the list.
Is there a way to say,
if x then f(x) and f(y)
?
As you are using F# immutable lists, the result of remove needs to be stored somewhere:
let rec isolate (l:'a list) =
match l with
| [] -> []
| x::xs ->
if memberof(x,xs)
then
let xs = remove (x,l)
isolate xs
else isolate xs
To answer your more general question:
let f _ = ()
let f' z = z
let x = true
let y = 42
let z = 3.141
if x then
f y
f' z |> ignore
The ignore is needed here because in F# there are no statements, just expressions, so you can think of if x then f' z as
if x then
f' z
else
()
and thus the first branch needs to return () as well.
In addition to CaringDev's answer.
You may look at this simple solution.
It is worth note, that it's not a fastest way to do this.
let rec isolate (acc : 'a list) (l : 'a list) =
match l with
| [] -> acc
| head :: tail ->
if memberof (head, tail)
then remove (head, tail) |> isolate (acc # [head])
else isolate (acc # [head]) tail
let recursiveDistinct = isolate []
let uniqValues = recursiveDistinct [ 1; 1; 2; 3] //returns [1;2;3]
let isolate list =
let rec isolateInner searchList commonlist =
match searchList with
| x::xs ->
if (memberof commonlist x) then
isolateInner xs commonlist
else
let commonlist = (x :: commonlist)
isolateInner xs commonlist
| [] -> reverse commonlist
isolateInner list []
This is part of an answer to your larger problem.
Notice that this does not use remove. Since you have to pass over each item in the original list and list are immutable, it is better to create a new list and only add the unique items to the new list, then return the new list.
I'm supposed to remove consecutive duplicates from an int list without using recursion and using only List.fold, map, filter, fold_left, fold_right.
I almost got it, but the problem with my code is that it checks if each element equals the 2nd element, and not the next element.
For example if let z = int list [3;1;4;5;5;1;1] my code will return [3;4;5] and not [3;1;4;5;1]. I'm not sure how to change it so filter uses a dynamically changing list parameter and not simply the original one (so it doesn't compare each element to the second element (1 in this case) each time):
let dupe (ls: int list) : int list =
List.filter (fun x -> if List.length ls = 0 then true else if x = List.hd (List.tl xs) then false else true) ls
The type of List.filter is this:
# List.filter;;
- : ('a -> bool) -> 'a list -> 'a list = <fun>
Notably, the filter function can see only one element of the list at a time. You need to see two consecutive elements to decide what to do, so I'd say List.filter won't do the job.
You're going to have to use map or one of the folds, I'd say. You can figure out which one(s) will work, with similar reasoning.
(I assume this is the sort of reasoning the assignment is supposed to illustrate. So I'm going to leave it there.)
Without rec
let remove = function
[] -> []
| x::tl ->
let (_,lxRes)=
List.fold_left (
fun (xPrec,lxRes) xCour ->
if xPrec=xCour then
(xCour,lxRes)
else
(xCour,lxRes#[xCour])
) (x+1,[]) (x::tl)
in
lxRes
Test:
# remove [3;1;4;5;5;1;1];;
- : int list = [3; 1; 4; 5; 1]
# remove [1;1];;
- : int list = [1]
# remove [1;1;1;1;2;2;3;4;5;5];;
- : int list = [1; 2; 3; 4; 5]
With rec (just for information)
let rec remove =
function
| [] -> []
| x::[] -> x::[]
| x::y::tl ->
if x=y then remove (y::tl)
else x::remove (y::tl)
Using just List.fold_left can be a little bit more concise than the previous answer. Of course, this will build up the list in reverse order, so we need to reverse the result.
let remove lst =
List.(
lst
|> fold_left
(fun acc x ->
match acc with
| [] -> [x]
| hd::_ when x = hd -> acc
| _ -> x::acc)
[]
|> rev
)
Of course, if you're not allowed to use List.rev we can reimplement it easily using List.fold_left, List.cons and Fun.flip.
let rev lst =
List.fold_left (Fun.flip List.cons) [] lst
I have written a function to deoptionalize an integer list and I would like to know if there is a better way to write it.
let deoptionalize (lst:'a option list) : 'a list =
List.map ~f:(fun x -> match x with Some x -> x | None -> assert false)
(List.filter ~f:(fun x -> x <> None) lst)
;;
In the assignment I am currently working its using map and filter is a must.
I suppose that a "hand-coded" solution (i.e. without map and filter) is easier to read, but if you really need to use them, here you go:
It seems that you are using the Core library. If so, I think your solution is not so bad, but can be written a bit more compact:
let deoptionalize lst =
List.filter ~f:(is_some) lst
|> List.map ~f:(function | Some x -> x | None -> assert false)
If you don't mind warnings (which I discourage you to do), you can even leave out some more:
let deoptionalize lst =
List.filter ~f:(is_some) lst
|> List.map ~f:(fun (Some x) -> x)
Actually, Core provides filter_map (thanks #Ramon Snir for the hint) which combines both, so you can use:
let deopt lst =
List.filter_map ~f:(fun x -> x) lst;;
In your case, I prefer doing in this way:
let deoptionalize l =
let rec deopt acc = function
| [] -> List.rev acc
| None::tl -> deopt acc tl
| Some x::tl -> deopt (x::acc) tl
in
deopt [] l
It is more clear and tail-recursive and performance is better
Another solution,
let deoptionalize l =
List.concat ## List.map (function | None -> [] | Some x -> [x]) l
What would be the syntax (if possible at all) for returning the list of lists ([[a]]) but without the use of empty list ([]:[a])?
(similar as the second commented guard (2) below, which is incorrect)
This is a function that works correctly:
-- Split string on every (shouldSplit == true)
splitWith :: (Char -> Bool) -> [Char] -> [[Char]]
splitWith shouldSplit list = filter (not.null) -- would like to get rid of filter
(imp' shouldSplit list)
where
imp' _ [] = [[]]
imp' shouldSplit (x:xs)
| shouldSplit x = []:imp' shouldSplit xs -- (1) this line is adding empty lists
-- | shouldSplit x = [imp' shouldSplit xs] -- (2) if this would be correct, no filter needed
| otherwise = let (z:zs) = imp' shouldSplit xs in (x:z):zs
This is the correct result
Prelude> splitWith (== 'a') "miraaaakojajeja234"
["mir","koj","jej","234"]
However, it must use "filter" to clean up its result, so I would like to get rid of function "filter".
This is the result without the use of filter:
["mir","","","","koj","jej","234"]
If "| shouldSplit x = imp' shouldSplit xs" is used instead the first guard, the result is incorrect:
["mirkojjej234"]
The first guard (1) adds empty list so (I assume) compiler can treat the result as a list of lists ([[a]]).
(I'm not interested in another/different solutions of the function, just the syntax clarification.)
.
.
.
ANSWER:
Answer from Dave4420 led me to the answer, but it was a comment, not an answer so I can't accept it as answer. The solution of the problem was that I'm asking the wrong question. It is not the problem of syntax, but of my algorithm.
There are several answers with another/different solutions that solve the empty list problem, but they are not the answer to my question. However, they expanded my view of ways on how things can be done with basic Haskell syntax, and I thank them for it.
Edit:
splitWith :: (Char -> Bool) -> String -> [String]
splitWith p = go False
where
go _ [] = [[]]
go lastEmpty (x:xs)
| p x = if lastEmpty then go True xs else []:go True xs
| otherwise = let (z:zs) = go False xs in (x:z):zs
This one utilizes pattern matching to complete the task of not producing empty interleaving lists in a single traversal:
splitWith :: Eq a => (a -> Bool) -> [a] -> [[a]]
splitWith f list = case splitWith' f list of
[]:result -> result
result -> result
where
splitWith' _ [] = []
splitWith' f (a:[]) = if f a then [] else [[a]]
splitWith' f (a:b:tail) =
let next = splitWith' f (b : tail)
in if f a
then if a == b
then next
else [] : next
else case next of
[] -> [[a]]
nextHead:nextTail -> (a : nextHead) : nextTail
Running it:
main = do
print $ splitWith (== 'a') "miraaaakojajeja234"
print $ splitWith (== 'a') "mirrraaaakkkojjjajeja234"
print $ splitWith (== 'a') "aaabbbaaa"
Produces:
["mir","koj","jej","234"]
["mirrr","kkkojjj","jej","234"]
["bbb"]
The problem is quite naturally expressed as a fold over the list you're splitting. You need to keep track of two pieces of state - the result list, and the current word that is being built up to append to the result list.
I'd probably write a naive version something like this:
splitWith p xs = word:result
where
(result, word) = foldr func ([], []) xs
func x (result, word) = if p x
then (word:result,[])
else (result, x:word)
Note that this also leaves in the empty lists, because it appends the current word to the result whenever it detects a new element that satisfies the predicate p.
To fix that, just replace the list cons operator (:) with a new operator
(~:) :: [a] -> [[a]] -> [[a]]
that only conses one list to another if the original list is non-empty. The rest of the algorithm is unchanged.
splitWith p xs = word ~: result
where
(result, word) = foldr func ([], []) xs
func x (result, word) = if p x
then (word ~: result, [])
else (result, x:word)
x ~: xs = if null x then xs else x:xs
which does what you want.
I guess I had a similar idea to Chris, I think, even if not as elegant:
splitWith shouldSplit list = imp' list [] []
where
imp' [] accum result = result ++ if null accum then [] else [accum]
imp' (x:xs) accum result
| shouldSplit x =
imp' xs [] (result ++ if null accum
then []
else [accum])
| otherwise = imp' xs (accum ++ [x]) result
This is basically just an alternating application of dropWhile and break, isn't it:
splitWith p xs = g xs
where
g xs = let (a,b) = break p (dropWhile p xs)
in if null a then [] else a : g b
You say you aren't interested in other solutions than yours, but other readers might be. It sure is short and seems clear. As you learn, using basic Prelude functions becomes second nature. :)
As to your code, a little bit reworked in non-essential ways (using short suggestive function names, like p for "predicate" and g for a main worker function), it is
splitWith :: (Char -> Bool) -> [Char] -> [[Char]]
splitWith p list = filter (not.null) (g list)
where
g [] = [[]]
g (x:xs)
| p x = [] : g xs
| otherwise = let (z:zs) = g xs
in (x:z):zs
Also, there's no need to pass the predicate as an argument to the worker (as was also mentioned in the comments). Now it is arguably a bit more readable.
Next, with a minimal change it becomes
splitWith :: (Char -> Bool) -> [Char] -> [[Char]]
splitWith p list = case g list of ([]:r)-> r; x->x
where
g [] = [[]]
g (x:xs)
| p x = case z of []-> r; -- start a new word IF not already
_ -> []:r
| otherwise = (x:z):zs
where -- now z,zs are accessible
r#(z:zs) = g xs -- in both cases
which works as you wanted. The top-level case is removing at most one empty word here, which serves as a separator marker at some point during the inner function's work. Your filter (not.null) is essentially fused into the worker function g here, with the conditional opening1 of a new word (i.e. addition1 of an empty list).
Replacing your let with where allowed for the variables (z etc.) to became accessible in both branches of the second clause of the g definition.
In the end, your algorithm was close enough, and the code could be fixed after all.
1 when thinking "right-to-left". In reality the list is constructed left-to-right, in guarded recursion ⁄ tail recursion modulo cons fashion.
For [1;2;3;4;5], I want to return [[1;2;3;4;5];[2;3;4;5];[3;4;5;];[4;5];[5];[]]
I'm trying to use the List library but I'm unsure how to. So far, I know I have to use List.tl to get the list without the first element
let rec tailsoflist (l : 'a list) : 'a list list =
match l with
[] -> [[]]
| x::xs -> l::(tails xs)
I did this recursively but now I want to just use the list library without using recursion.
let tails (l : 'a list) : 'a list list
EDIT: Sorry guys, what I specified for the function to return is incorrect. Just updated it with the correct output.
As I said in the comment, these are not the tails of l but copies of the tails of l:
# let tails l = List.fold_right (fun e acc -> (e::(List.hd acc))::acc) l [[]] ;;
val tails : 'a list -> 'a list list = <fun>
# tails [1; 2; 3; 4] ;;- : int list list = [[1; 2; 3; 4]; [2; 3; 4]; [3; 4]; [4]; []]
There is no good way to write that function in terms of the built-in functions.
The answer you give in your question is fine but it would be more idiomatic to not annotate the types and use function:
let rec tails = function
| [] -> [[]]
| _::xs' as xs -> xs::tails xs'
Other languages, like F#, provide a List.unfold function that tails can be written in terms of.
Ah, the old trick to accumulate on the original list to cast tails as a catamorphism. This is done without explicit recursion using just functions on the List module:
let tails l = List.rev ( [] :: snd (List.fold_right
(fun _ (t,ts) -> List.tl t, t::ts) l (l, [])) )
It produces the tails as you expect:
# tails [1;2;3;4;5];;
- : int list list = [[1; 2; 3; 4; 5]; [2; 3; 4; 5]; [3; 4; 5]; [4; 5]; [5]; []]
and the tails are the actual structural tails of the input list, so that List.tl l == List.hd (List.tl (tails l)).
"Without using recursion"... why ? Recursion is a useful tool, even outside the List library.
let rec suffixes = function
| [] -> [[]]
| hd::tl as suff -> suff :: suffixes tl
Your function (which doesn't compile because you use tails instead of tailsoflist) returns the list of suffixes of a list. Due to the list structure, it's easier to compute than the prefixes.
You can express the prefixes from the suffixes :
let prefixes li = List.map List.rev (suffixes (List.rev li));;
You could do a direct version using an accumulator:
let prefixes li =
let rec pref acc = function
| [] -> List.rev acc :: []
| hd::tl -> List.rev acc :: pref (hd :: acc) tl
in pref [] li
and express it using List.fold_left if you want to avoid recursion, but this is convoluted so you should prefer the direct version in my opinion:
let prefixes li =
let acc, res =
List.fold_left
(fun (acc, res) e -> (e :: acc), (List.rev acc :: res))
([], []) li in
List.rev acc :: res
Finally, it is possible to destroy your brain with a version using continuations, but I don't remember the exact code. Roughly, the continuation is equivalent to the "accumulator" of the direct version.