Asking about ML recursive function - sml

I have been doing with ml function and got some annoying things.
I will explain it with simple code.
For example if there is a list(int*int) and I want to examine that there are some tuples that contains 3 for the first element.
L = [(1,2),(2,3),(3,5),(3,4)]
so in this list, I want to get 5 and 4.
However, in ML, the function is recursive, so if I write code like this.
fun a(list) =
if #1(hd(list)) = 3 then #2(hd(list))
else a(tl(list))
in this simple function, it can get 5 but not 4 because once it detects that (3,5) is satisfied the condition it returns 5 and the function finishes.
Is there any way to get the 4 as well?

I don't know ml but basically instead of doing else you need to do this:
fun a(list) =
if list = nil then nil
else
if #1(hd(list)) = 3
then
#2(hd(list)) :: a(tl(list))
else
a(tl(list))
(I am gradually editing this response as I learn more about ML :)

You forgot to call the function recursively on the tail of the list where the condition held.
In ML, you almost never use hd and tl but use pattern matching instead. And you can pattern-match on tuples for more readability:
fun filter [] = []
| filter ((x, y)::xys) = if x = 3
then y::(filter xys)
else filter xys
And high-order functions on List structure is another option in case you would like to use them.

Related

How to implement recursive function to simplify polynomial terms with sorted tuple list?

I'm trying to implement a function to add like terms of a sorted list of tuples (first number represents polynomial's constant, the second represents the power). I'm an ocaml noob and don't really know what I'm doing wrong or how to do this correctly.
I tried to write it, but it doesn't work
https://gyazo.com/d37bb66d0e6813537c34225b6d4048d0
let rec simp list =
match list with
| (a,b)::(c,d)::remainder where b == d -> (a+c,b)::simp(remainder)
| (a,b)::(c,d)::remainder where b != d -> (a,b)::(c,d)::simp(remainder)
| _ -> list;;
This should combine all the terms with the same second value and just return one tuple with their first values added to the new list. ie: [(3,2);(4,2)] -> [(7,2)].
I am not familiar with the where keyword - there is ocaml-where which provides it, but it seems to be doing something different than what you are expecting. As such, the syntax is just wrong, and where is unexpected.
You probably meant when instead of where.

Combination takeWhile, skipWhile

In F#, I find when I want to use takeWhile, I usually also want to use skipWhile, that is, take the list prefix that satisfies a predicate, and also remember the rest of the list for subsequent processing. I don't think there is a standard library function that does both, but I can write one easily enough.
My question is, what should this combination be called? It's obvious enough that there should be a standard name for it; what is it? Best I've thought of so far is split, which seems consistent with splitAt.
span is another name I've seen for this function. For example, in Haskell
This part of your question stood out to me (emphasis mine):
take the list prefix that satisfies a predicate, and also remember the rest of the list for subsequent processing
I am guessing that you want to recurse with the rest of the list and then apply this splitting function again. This is what I have wanted to do a few times before. Initially, I wrote the function that I think you are describing but after giving it more thought I realised that there might be a more general way to think about it and avoid the recursion completely, which usually makes code simpler. This is the function I came up with.
module List =
let groupAdjacentBy f xs =
let mutable prevKey, i = None, 0
xs
|> List.groupBy (fun x ->
let key = f x
if prevKey <> Some key then
i <- i + 1
prevKey <- Some key
(i, key))
|> List.map (fun ((_, k), v) -> (k, v))
let even x = x % 2 = 0
List.groupAdjacentBy even [1; 3; 2; 5; 4; 6]
// [(false, [1; 3]); (true, [2]); (false, [5]); (true, [4; 6])]
I found this one easier to name and more useful. Maybe it works for your current problem. If you don't need the group keys then you can get rid of them by adding |> List.map snd.
As much as I usually avoid mutation, using it here allowed me to use List.groupBy and avoid writing more code.
.slice could capture the intent of a contiguous range:
List.slice skipPredicate takePredicate

SML/NJ - Print a list mid-execution

I wanted to utilize the print function inside an SML program for sort of debugging purposes to print integer list type data, inside the function and during execution, e.g. inside a let block. However, as I saw, print can only print string type data. I cannot wait for the result to return to print what I want, because the function I created branches during execution and creates many different lists, and I want to see what is the resulting list at the end of each branch.
Therefore, is there a way to print a list inside of a function, as I would print a string?
If it is an int list you can do something like this:
fun printIntList ints = app (fn i => print(Int.toString i ^" ")) ints;
Then printIntList [1,2,3] will print 1 2 3
You can do similar things for other types.
On edit: This is the best you can do with straight SML. SML/NJ has its own extensions including "access to compiler internals" and "user-customizable pretty printing" which sounds promising -- though I have little experience with their extensions to the standard library.
Simple function for turning a list of ints into a string:
fun intlistToString [] = ""
| intlistToString [x] = Int.toString x
| intlistToString (x::xs) = Int.toString x ^ ", " ^ intlistToString xs
Then you can use print (intlistToString myList) instead of print myList. It won't print the square brackets around the list, not without a little more code, but I'll leave that as an exercise because I'm lazy.

Removing the first instance of x from a list

I am new to Haskell and have been trying to pick up the basics.
Assume I have the following list y:
3:3:2:1:9:7:3:[]
I am trying to find a way to delete the first occurrence of 3 in list y. Is this possible using simple list comprehension?
What I tried (this method deletes all instances from a list):
deleteFirst _ [] = []
deleteFirst a (b:bc) | a == b = deleteFirst a bc
| otherwise = b : deleteFirst a bc
No, it's not possible using a list comprehension. In a list comprehension you make a decision which element to keep based on that element only. In your example, you want to treat the first 3 you encounter differently than other 3s (because you only want to remove the first one), so the decision does not depend on the element alone. So a list comprehension won't work.
Your attempt using a recursive function is already pretty close, except that, as you said, it removes all instances. Why does it remove all instances? Because after you removed the first one, you call deleteFirst again on the rest of the list, which will remove the next instance and so on. To fix this, just do not call deleteFirst again after removing the first instance. So just use bc instead of deleteFirst a bc in that case.
as other already mentioned list comprehension is not an appropriate solution to this task (difficult to terminate the execution at one step).
You've almost written the correct solution, just in the case of equality with the matched value you had to terminate the computation by returning the rest of list without the matched element:
deleteFirst _ [] = []
deleteFirst a (b:bc) | a == b = bc
| otherwise = b : deleteFirst a bc
> print $ deleteFirst 3 (3:3:2:1:9:7:3:[])
> [3,2,1,9,7,3]
I don’t believe it is possible to do this with list comprehension (at least not in in any idiomatic way).
Your deleteFirst works almost. All you need to change to fix is is to stop deleting after the first match, i.e. replace deleteFirst a bc in the first clause by bc.
sepp2k's remarks about list comprehensions are an important thing to understand; list operations like map, filter, foldr and so on treat all list items uniformly, and the important thing to understand about them is what information is available at each step, and how each step's result is combined with those of other steps.
But the aspect I want to stress is that I think you should really be trying to solve these problems in terms of library functions. Adapting the solution from this older answer of mine to your problem:
deleteFirst x xs = beforeX ++ afterX
-- Split the list into two pieces:
-- * prefix = all items before first x
-- * suffix = all items after first x
where (beforeX, xAndLater) = break (/=x) xs
afterX = case xAndLater of
[] -> []
(_:xs) -> xs
The trick is that break already has the "up to first hit" behavior built in it. As a further exercise, you can try writing your own version of break; it's always instructive to learn how to write these small, generic and reusable functions.

Extract a from [a]

how can I easily take the following
[4]
and return the following:
4
I know that [4]!!0 works but doesn't seem to be a good strategy...
Just pattern match it:
getSingleton [a] = a
head is the normal answer, which you see three of (one with a custom name) - this is functionally the same as what you already know (x !! 0 ~ head x). I strongly suggest against partial functions unless you can prove (with local knowledge) that you'll never pass an empty list and result in a run-time exception.
If your function doesn't guarantee a non-empty list then use listToMaybe :: [a] -> Maybe a:
> listToMaybe [4]
Just 4
> listToMaybe [5,39,-2,6,1]
Just 5
> listToMaybe []
Nothing -- A 'Nothing' constructor instead of an exception
Once you have the Maybe a you can pattern match on that, keep it as Maybe and use fmap or a Maybe monad, or some other method to perform further operations.
Alternatively to gatoatigrado's solution you can also use the head function, which extracts the first element of a list, but will also work on lists with more than one element and additionally is a standard function in the Prelude. You just have to be careful not to apply it to empty lists or you will get a runtime exception.
Prelude> head [4]
4
Prelude> head []
*** Exception: Prelude.head: empty list
If you want this first item in a list you can just do
head [4]
[] is a monad. So you use the monad "extract" operation, <-
double x = 2*x
doubleAll xs = do x <- xs
return (double x)
Of course, the result of the monadic computation is returned in the monad. ;)