I am writing a recursive ML function, that takes a string, and an index value, and splits the string at the given index. The function should return a list containing two strings.
I understand that I need two base cases one to check if the index has been reached, and one to check if the string is out of characters. I am stuck on how I assign the characters to different strings. Note, I used a helper function to clean up the initial call, so that explode will not need to be typed on every function call.
fun spliatHelp(S, num) =
if null S then nil
else if num = 0 then hd(S) :: (*string2 and call with tl(S)*)
else hd(S) :: (*string1 and call with tl(S)*)
fun spliat(S, num) =
spliatHelp(explode(S), num);
From an input of spliat("theString", 3);
My ideal output would be ["the", "String"];
For the num = 0 case, you just need to return [nil, S] or (equivalently) nil :: S :: nil.
For the other case, you need to make the recursive call spliatHelp (tl S, num - 1) and then examine the result. You can use either a let expression or a case expression for that, as you prefer. The case expression version would look like this:
case spliatHelp (tl S, num - 1)
of nil => nil (* or however you want to handle this *)
| [first, second] => [hd S :: first, second]
| raise (Fail "unexpected result")
Incidentally, rather than returning a string list with either zero or two elements, I think it would be better and clearer to return a (string * string) option. (Or even just a string * string, raising an exception if the index is out of bounds.)
Related
So im really confused as i am new to sml and I am having trouble with syntax of how i want to create my function.
the instructions are as follows...
numberPrefix: char list → string * char list
Write a function named numberPrefix that returns (as a pair) a string representing the digit characters at the
beginning of the input list and the remaining characters after this prefix. You may use the Char.isDigit and
String.implode functions in your implementation.
For example,
numberPrefix [#"a", #"2", #"c", #" ", #"a"];
val it = ("", [#"a", #"2", #"c", #" ", #"a") : string * char list
numberPrefix [#"2", #"3", #" ", #"a"];
val it = ("23", [#" ", #"a"]) : string * char list
Here is my code so far...
fun numberPrefix(c:char list):string*char list =
case c of
[] => []
|(first::rest) => if isDigit first
then first::numberPrefix(rest)
else
;
I guess what i am trying to do is append first to a seperate list if it is indeed a digit, once i reach a member of the char list then i would like to return that list using String.implode, but I am banging my head on the idea of passing in a helper function or even just using the "let" expression. How can I essentially create a seperate list while also keeping track of where i am in the original list so that I can return the result in the proper format ?
First of all, the function should produce a pair, not a list.
The base case should be ("", []), not [], and you can't pass the recursive result around "untouched".
(You can pretty much tell this from the types alone. Pay attention to types; they want to help you.)
If you bind the result of recursing in a let, you can access its parts separately and rearrange them.
A directly recursive take might look like this:
fun numberPrefix [] = ("", [])
| numberPrefix (cs as (x::xs)) =
if Char.isDigit x
then let val (number, rest) = numberPrefix xs
in
((str x) ^ number, rest)
end
else ("", cs);
However, splitting a list in two based on a predicate – let's call it "splitOn", with the type ('a -> bool) -> 'a list -> 'a list * 'a list – is a reasonably useful operation, and if you had that function you would only need something like this:
fun numberPrefix xs = let val (nums, notnums) = splitOn Char.isDigit xs
in
(String.implode nums, notnums)
end;
(Splitting left as an exercise. I suspect that you have already implemented this splitting function, or its close relatives "takeWhile" and "dropWhile".)
I've tried to write a function which returns a repeated element
findMul :: [String] -> String
findMul [] = []
findMul s
|ss!!0 == ss!!1 = ss!!0
|otherwise = findMul (tail s)
where
ss = sort s
sort :: [String] -> [String]
sort [] = []
sort (x:ys) = (sort ls) ++ [x] ++ (sort gs)
where
ls = [y | y<-ys, y<=x]
gs = [y | y<-ys, y>x ]
This seems to work when tested with the input
findMul ["d","c","b","a","a"]
which correctly returns
"a"
but when I test it with a slightly different input
findMul ["d","c","b","b","a"]
which returns the error
*** Exception: Prelude.(!!): index too large
Could anyone possibly explain what the error means? And possibly why it occurs?
Your sort function is fine; the problem lies in the definition of your findMul function. Note that the second pattern,
findMul s
is used in case list s is nonempty. In particular, it's used in case s be a singleton list (a list composed of only one element).
Moreover, lists s and ss always have the same length; therefore, if s only has one element, ss also has only one element.
However, in ss!!1, you're trying to access the second element of ss, which doesn't exist if s is a singleton list. You're essentially trying to access an element beyond the actual length (i.e. 1) of list ss! That's why Haskell is yelling at you:
*** Exception: Prelude.(!!): index too large
Your pattern matching for findMul can take a single element list
findMul ["b"]
when this happens, the ss list is also of length 1, but you are using the second element in it in the guard ss!!1.
This is the error.
Using ! for list access is often not the best idea. Use pattern matching, and things become clearer.
findMul (x:y:rest) = if x == y then y else findMul (y:rest)
findMul [x] = x -- the branch you originally missed
findMul [] = undefined -- or what you'd prefer
It also becomes obvious that you find the first repetition only. Consider going full RLE :)
I'm new to SML and I'm attempting to get the index of an item in a list. I know that using List.nth will give me the value of an item at a index position, but I want the index value. There may even be a built in function that I'm not aware of. In my case, the list will not contain duplicates so if the item is in the list I get the index, if not it returns ~1. Here is the code I have so far. It works, but I don't think it is very clean:
val L=[1,2,3,4,5];
val m=length L-1;
fun Index(item, m, L)=if m<0 then ~1 else
if List.nth(L, m)=item then m else Index(item,m-1,L);
To elaborate on my previous comment, I suggest some changes for an implementation that fits better in the ML idiom:
fun index(item, xs) =
let
fun index'(m, nil) = NONE
| index'(m, x::xr) = if x = item then SOME m else index'(m + 1, xr)
in
index'(0, xs)
end
The individual changes are:
Have index return a value of type int option. NONE means the item is not in the list, SOME i means it is in the list, and the index of its first occurrence is i. This way, no special values (~1) need be used and the function's intended usage can be inferred from its type.
Hide the parameter m by renaming the function to index' and wrapping it into an outer function index that calls it with the appropriate arguments. The prime character (`) often indicates auxiliary values.
Use pattern matching on the list to get to the individual elements, eliminating the need for List.nth.
Also note that most commonly, function and variable names begin with a lowercase letter (index rather than Index), while capital letters are used for constructor constants (SOME) and the like.
I would like to propose a simpler and less efficient version of this index function. I agree that it is not as desirable to use exceptions rather than int option, and that it is not tail-recursive. But it is certainly easier to read and thus may serve as learning material:
fun index (x, []) = raise Subscript
| index (x, y::ys) =
if x = y then 0 else 1 + index (x, ys)
fun index(list,n)=
= if n=0 then hd(list) else index(tl(list),n-1);
val index = fn : 'a list * int -> 'a
index([1,2,3,4,5],2);
val it = 3 : int
index([1,2,3,4,5],0);
val it = 1 : int
How to create a function in Haskell that returns the fifth element from a list.
Something like this:
fifth [] = []!!4
Should return this:
*Main> fifth [1,2,3,20,30,40]
30
Simply use:
fifth :: [a] -> a
fifth l = l !! 4
Using fifth [] like you suggest is wrong since that will pattern match the list against the empty list — you simply want to bind a variable name to the full list so that you can use the !! function afterwards.
You can even define the function as:
fifth :: [a] -> a
fifth = (!!4)
Here we use partial application: you normally think of !! as a function taking two arguments: a list and an integer. We can provide it with one of the arguments and get a new function (fifth) that only takes a list. When we provide (!!4) with a list, it returns the fifth element:
Prelude> let fifth = (!!4)
Prelude> fifth [1,2,3,20,30,40]
30
The function is of course a partial function since it will fail for small lists:
Prelude> (!!4) [1,2,3,20]
*** Exception: Prelude.(!!): index too large
That's to be expected. If you want, you can make it safe by letting it return Maybe a instead of a::
fifth :: [a] -> Maybe a
fifth (a:b:c:d:e:rest) = Just e
fifth _ = Nothing
Here the first pattern will match lists of length 5 or more, and the second pattern matches anything not matched by the first. You use it like this:
*Main> fifth [1,2,3,20,30,40]
Just 30
*Main> fifth [1,2,3,20]
Nothing
You have now forced yourself to always pattern match the result of fifth against either Just a or Nothing. This means that when you code calls fifth someList, then it must take into account that someList might be too short. That way you can ensure at compile time that there wont be any runtime errors from this function.
I would define a safe-indexing operator !!! and then define fifth in terms of !!!.
(!!!) :: [a] -> Int -> Maybe a
xs !!! n | n < 0 = Nothing
[] !!! _ = Nothing
(x : _) !!! 0 = Just x
(_ : xs) !!! n = xs !!! (n - 1)
fifth :: [a] -> Maybe a
fifth = (!!! 4)
Another unsafe variant would be
fifth = head . drop 4
But hey, sometimes one just knows this damn list will have more than 4 elements. The type system is just not powerful enough to express it (using standard lists, that is).
I'm very new with Haskell, only starting to learn it.
I'm using "Learn You a Haskell for Great Good!" tutorial for start, and saw example of solving "3n+1" problem:
chain :: (Integral a) => a -> [a]
chain 1 = [1]
chain n
| even n = n:chain (n `div` 2)
| odd n = n:chain (n*3 + 1)
numLongChains :: Int
numLongChains = length (filter isLong (map chain [1..100]))
where isLong xs = length xs > 15
so, numLongChains counts all chains that longer 15 steps, for all numbers from 1 to 100.
Now, I wanna my own:
numLongChains' :: [Int]
numLongChains' = filter isLong (map chain [1..100])
where isLong xs = length xs > 15
so now, I wanna not to count these chains, but return filtered list with these chains.
But now I get error when compiling:
Couldn't match expected type `Int' with actual type `[a0]'
Expected type: Int -> Bool
Actual type: [a0] -> Bool
In the first argument of `filter', namely `isLong'
In the expression: filter isLong (map chain [1 .. 100])
What can be the problem?
The type signature of numLongChains is probably not correct. Depending on what you want to do, one of the following is needed:
You simply want to count those chains, your function numLongChains obviously shall return a number, change the first line to length $ filter isLong (map chain [1..100]) and the type to Int
You want to return a list of lengths of the long chains. In this case, the type signature is fine, but you need to return a length. I'd suggest you, the calculate the length before filtering and filter on it. The function's body becomes filter (>15) (map (length . chain) [1..100]).
You want to return all chains that are longer than 15 chars. Just change the signature to [[Int]] (A list of chains (lists) of Ints) and you're fine.
FUZxxl is right. You are going to want to change the type signature of your function to [[Int]]. As you are filtering a list of lists and only selecting the ones that are sufficiently long, you will have returned a lists of lists.
One note about reading Haskell compile-time debugger/errors. This error may seem strange. It says you had [a0] -> Bool but you were expecting Int -> Bool. This is because that the type checker assumes that, from the signature of your numLongChains' function, you are going to need a filter function that checks Ints and returns a list of acceptable ones. The only way to filter over a list and get [Int] back is to have a function that takes Ints and returns Bools (Int -> Bool). Instead, it sees a function that checks length. Length takes a list, so it guesses that you wrote a function that checks lists. ([a0] -> Bool). Sometimes, the checker is not as friendly as you would like it to be but if you look hard enough, you will see that 9 times out of 10, a hard to decipher error is the result of such as assumptions.