I am new to SML and don't understand too about the syntax.
I am doing a practice on checking palindrome without reversing the list. Here is my code
fun symmetric(i,n,inlist) =
if List.nth(inlist,i-1) = List.nth(inlist,n-i)
then true
else
false;
fun palindrome(n, inlist) =
let
val i = ref 1
in
while !i < n do (
if symmetric(!i,!n,!inlist) = false
then false
else ()
i := !i + 1
)
true
end;
I got errors in fun palindrome only, but can't fix it by myself.
You can even make a palindrome checker without converting your string to a list:
fun palindrome s =
let fun check i j =
i >= j orelse
String.sub (s, i) = String.sub (s, j) andalso
check (i+1) (i-1)
in check 0 (String.size s - 1) end
Here is some feedback for your code:
Naturally, consider using recursion rather than iteration.
A common problem for non-functional programmers is that they seem to want to execute many statements in succession only for their side-effect. In functional programming you rely very much on the value of every expression to guide the result of the program. There is a ; operator, though, and it could be used like this:
fun palindrome s =
let val i = ref 0
val j = ref (String.size s - 1)
val result = ref true
in while !i < !j do
(if String.sub (s, !i) = String.sub (s, !j)
then (i := !i + 1 ; j := !j - 1)
else (i := !j ; result := false))
; !result
end
Often, though, if you want to do multiple things in a row, let-expressions are just as neat as the ; operator.
The code
if A = false
then false
else B
can be written as
if not (A)
then false
else B
which can further be improved into
if A
then B
else false
which is really the same as
A andalso B
So the morals are:
Instead of A = false, write not A (and instead of A = true, write A).
You can always replace if ... then <true/false> else <true/false> with some combination of andalso and orelse. That is, if-then-else is never necessary when the result type is bool (but you might still prefer it if the logic is very convoluted).
If the restriction against reversing a list was intended to ban using the built-in rev but not computations which implicitly reverse lists, here is a stack-based approach. The idea is to push characters onto a stack (represented as a list), and then pop them off, checking them against the original list of characters. If either the stack or the original list empty first, or if the item popped doesn't match the corresponding char in the original list -- it isn't a plalindrome
fun pushAll [] stack = stack
| pushAll (x::xs) stack = pushAll xs (x::stack)
fun popCheck [] [] = true
| popCheck [] _ = false
| popCheck _ [] = false
| popCheck (x::xs) (y::ys) = x = y andalso popCheck xs ys
fun palindrome s =
let val chars = explode s
val stack = pushAll chars []
in
popCheck chars stack
end;
Related
I am newbie to SML, trying to write recursive program to delete chars from a string:
remCharR: char * string -> string
So far wrote this non-recursive prog. Need help to write recursive one.
- fun stripchars(string,chars) = let
= fun aux c =
= if String.isSubstring(str c) chars then
= ""
= else
= str c
= in
= String.translate aux string
= end
= ;
You have already found a very idiomatic way to do this. Explicit recursion is not a goal in itself, except perhaps in a learning environment. That is, explicit recursion is, compared to your current solution, encumbered with a description of the mechanics of how you achieve the result, but not what the result is.
Here is one way you can use explicit recursion by converting to a list:
fun remCharR (c, s) =
let fun rem [] = []
| rem (c'::cs) =
if c = c'
then rem cs
else c'::rem cs
in implode (rem (explode s)) end
The conversion to list (using explode) is inefficient, since you can iterate the elements of a string without creating a list of the same elements. Generating a list of non-removed chars is not necessarily a bad choice, though, since with immutable strings, you don't know exactly how long your end-result is going to be without first having traversed the string. The String.translate function produces a list of strings which it then concatenates. You could do something similar.
So if you replace the initial conversion to list with a string traversal (fold),
fun fold_string f e0 s =
let val max = String.size s
fun aux i e =
if i < max
then let val c = String.sub (s, i)
in aux (i+1) (f (c, e))
end
else e
in aux 0 e0 end
you could then create a string-based filter function (much alike the String.translate function you already found, but less general):
fun string_filter p s =
implode (fold_string (fn (c, res) => if p c then c::res else res) [] s)
fun remCharR (c, s) =
string_filter (fn c' => c <> c') s
Except, you'll notice, it accidentally reverses the string because it folds from the left; you can fold from the right (efficient, but different semantics) or reverse the list (inefficient). I'll leave that as an exercise for you to choose between and improve.
As you can see, in avoiding String.translate I've built other generic helper functions so that the remCharR function does not contain explicit recursion, but rather depends on more readable high-level functions.
Update: String.translate actually does some pretty smart things wrt. memory use.
Here is Moscow ML's version of String.translate:
fun translate f s =
Strbase.translate f (s, 0, size s);
with Strbase.translate looking like:
fun translate f (s,i,n) =
let val stop = i+n
fun h j res = if j>=stop then res
else h (j+1) (f(sub_ s j) :: res)
in revconcat(h i []) end;
and with the helper function revconcat:
fun revconcat strs =
let fun acc [] len = len
| acc (v1::vr) len = acc vr (size v1 + len)
val len = acc strs 0
val newstr = if len > maxlen then raise Size else mkstring_ len
fun copyall to [] = () (* Now: to = 0. *)
| copyall to (v1::vr) =
let val len1 = size v1
val to = to - len1
in blit_ v1 0 newstr to len1; copyall to vr end
in copyall len strs; newstr end;
So it first calculates the total length of the final string by summing the length of each sub-string generated by String.translate, and then it uses compiler-internal, mutable functions (mkstring_, blit_) to copy the translated strings into the final result string.
You can achieve a similar optimization when you know that each character in the input string will result in 0 or 1 characters in the output string. The String.translate function can't, since the result of a translate can be multiple characters. So an alternative implementation uses CharArray. For example:
Find the number of elements in the new string,
fun countP p s =
fold_string (fn (c, total) => if p c
then total + 1
else total) 0 s
Construct a temporary, mutable CharArray, update it and convert it to string:
fun string_filter p s =
let val newSize = countP p s
val charArr = CharArray.array (newSize, #"x")
fun update (c, (newPos, oldPos)) =
if p c
then ( CharArray.update (charArr, newPos, c) ; (newPos+1, oldPos+1) )
else (newPos, oldPos+1)
in fold_string update (0,0) s
; CharArray.vector charArr
end
fun remCharR (c, s) =
string_filter (fn c' => c <> c') s
You'll notice that remCharR is the same, only the implementation of string_filter varied, thanks to some degree of abstraction. This implementation uses recursion via fold_string, but is otherwise comparable to a for loop that updates the index of an array. So while it is recursive, it's also not very abstract.
Considering that you get optimizations comparable to these using String.translate without the low-level complexity of mutable arrays, I don't think this is worthwhile unless you start to experience performance problems.
I am new to ruby and working on a problem but I don't know how to figure it out.
I want to write a function that return true if each consecutive element is a power of the previous element, otherwise return false
for example: if I have a list [2;4;8;16] the function should return true
function should return false , [3; 7; 9;]
let consec_ele element = match element with
[] -> true
h::t ->
if h > t then false
else
if t/h = 0 && t mod h = 0 then true
;;
i just can't figure out how to make it work and that so recursively.
Well, you first need to formalise your problem :
if my list is empty, then true
if my list is not, then it starts with a number n
if n = 1, then I need to start again because a^0 = 1 for all a
if n > 0 then I call a new function check on the rest of the list, tl, acting like this :
if tl is empty, then true
else tl starts with n' then if n' = n * n then I call check recursively on the rest and I need to keep the fact that I'm now checking for n * n * n ...
If n <= 0 then false
In OCaml this would be
let consec_ele l =
let rec cer b = function
| [] -> true
| n :: tl ->
if n <= 0 then false
(* We can start again for the first 1 we see, but if our
* list is [1; 1; 1; ...; 1] then we need to stop
* That's why we have this boolean b which is true and once
* we see 1 as the head of our list we swap it to false
*)
else if n = 1 then b && cer false tl
else
let rec check p = function
| [] -> true
| n' :: tl -> n' = pow n p && check (p + 1) tl
in check 1 tl
in cer true l;;
(For the pow function, I let you write it ;-) Of course, this can be bad because you could have an overflow, maybe you'd prefer to see if n' ^ (1/p) = n (the pth root of n' (why don't we have LaTeX mathmode on stackoverflow ? :-())
Being able to pattern-match on the first two elements in a list makes this trivial. Obviously an empty list is true, and a list with one element is also true. Otherwise, if we consider the first two elements, if the second is a power of the first, the function is true, and we can discard the first and consider the rest of the list recursively. Otherwise, the result is clearly false.
let rec consec_ele =
function
| [] | [_] -> true
| a::(b::_ as tl) when is_power_of a b -> consec_ele tl
| _ -> false
As a note, your test case of [2;4;8;16] should actually return false as 8 is a multiple, but not a power of 4.
I have a character list [#"h", #"i", #" ", #"h", #"i"] which I want to get the first word from this (the first character sequence before each space).
I've written a function which gives me this warning:
stdIn:13.1-13.42 Warning: type vars not generalized because of value
restriction are instantiated to dummy types (X1,X2,...)
Here is my code:
fun next [] = ([], [])
| next (hd::tl) = if(not(ord(hd) >= 97 andalso ord(hd) <= 122)) then ([], (hd::tl))
else
let
fun getword [] = [] | getword (hd::tl) = if(ord(hd) >= 97 andalso ord(hd) <= 122) then [hd]#getword tl else [];
in
next (getword (hd::tl))
end;
EDIT:
Expected input and output
next [#"h", #"i", #" ", #"h", #"i"] => ([#"h", #"i"], [#" ", #"h", #"i"])
Can anybody help me with this solution? Thanks!
This functionality already exists within the standard library:
val nexts = String.tokens Char.isSpace
val nexts_test = nexts "hi hi hi" = ["hi", "hi", "hi"]
But if you were to build such a function anyway, it seems that you return ([], []) sometimes and a single list at other times. Normally in a recursive function, you can build the result by doing e.g. c :: recursive_f cs, but this is assuming your function returns a single list. If, instead, it returns a tuple, you suddenly have to unpack this tuple using e.g. pattern matching in a let-expression:
let val (x, y) = recursive_f cs
in (c :: x, y + ...) end
Or you could use an extra argument inside a helper function (since the extra argument would change the type of the function) to store the word you're extracting, instead. A consequence of doing that is that you end up with the word in reverse and have to reverse it back when you're done recursing.
fun isLegal c = ord c >= 97 andalso ord c <= 122 (* Only lowercase ASCII letters *)
(* But why not use one of the following:
fun isLegal c = Char.isAlpha c
fun isLegal c = not (Char.isSpace c) *)
fun next input =
let fun extract (c::cs) word =
if isLegal c
then extract cs (c::word)
else (rev word, c::cs)
| extract [] word = (rev word, [])
in extract input [] end
val next_test_1 =
let val (w, r) = next (explode "hello world")
in (implode w, implode r) = ("hello", " world")
end
val next_test_2 = next [] = ([], [])
I'm working on a program that appends either a '+' or '-' to an element of a list, depending on whether the index of that element is odd or even (i.e an alternating sums list).
However, I'm having trouble identifying what the index of each element is. I have code that I believe should append the correct symbol, using if statements and mod
fun alternating([]) = 0
| alternating(l) =
if List.nth(l,hd(l)) mod 2 == 0 then '+'#hd(l)#alternating(tl(l))
else '-'#hd(l)#alternating(tl(l))
However, List.nth(l,hd(l)) always returns the element at the second index, not the first.
On the off chance that you really just want to negate integers them so you can pass them into some kind of summation, I would just negate the argument if it's odd. Using mutual recursion one can do it without any explicit index bookkeeping:
fun alternate l =
let
fun alternate1 [] = []
| alternate1 (x::xs) = (~x) :: alternate2 xs
and alternate2 [] = []
| alternate2 (x::xs) = x :: alternate1 xs
in
alternate1 l
end
It works like so:
- alternate [1,2,3,4];
val it = [~1,2,~3,4] : int list
I would strongly encourage you to use pattern matching instead of hd.
Edit discussing hd
As a rule of thumb, if you need hd you probably need tl as well. hd is a partial function--it's going to throw Empty if your list is empty. If you pattern match, you conveniently get variables for the head and tail of the list right there, and you get a visual reminder that you need to handle the empty list. It's more aesthetically pleasing, IMO, to see:
fun foo [] = ...
| foo (x::xs) = ...
than the equivalent
fun foo l =
if null l
then ...
else (hd l) ... (tl l)
In other words, you get shorter, cleaner code with an automatic reminder to make it correct. Win/win. To my knowledge there's no significant advantage to doing it the other way. Of course, you may find yourself in a situation where you know the list will have at least one element and you don't need to do anything else. You still have to consider the cases you're given, but it's a good rule of thumb.
If you want to decorate your list with an index you could try something like the following
fun add_index l =
let
fun add_index_helper (nil, _) = nil
| add_index_helper (h::tl,i) = (h,i) :: add_index_helper (tl,1+i)
in
add_index_helper (l,0)
end
val x = add_index [0,1,4,9,16,25]
but you can also just directly compute parity with the same method
fun add_sign l =
let
fun add_sign_helper (nil, _) = nil
| add_sign_helper (h::tl,i) = (h,i) :: add_sign_helper (tl,1-i)
in
add_sign_helper (l,0)
end
val y = add_sign [0,1,4,9,16,25]
then you can map the parity to a string
fun sign_to_char (x,0) = (x,"+")
| sign_to_char (x,_) = (x,"-")
val z = List.map sign_to_char y
or you can just add the sign directly
fun add_char l =
let
fun add_char_helper (nil, _) = nil
| add_char_helper (h::tl,0) = (h,"+") :: add_char_helper (tl,1)
| add_char_helper (h::tl,_) = (h,"-") :: add_char_helper (tl,0)
in
add_char_helper (l,0)
end
val zz = add_char [0,1,4,9,16,25]
Alternatively if you had a string list and you wanted to add chars you could try something like this
fun signs L =
let
datatype parity = even | odd
fun signs_helper ( nil ,_) = nil
| signs_helper (x::xs,even) = ("+" ^ x) :: signs_helper(xs,odd)
| signs_helper (x::xs,odd) = ("-" ^ x) :: signs_helper(xs,even)
in
signs_helper (L,even)
end
val z = signs ["x","2y","3z","4"]
(* this gives you val z = ["+x","-2y","+3z","-4"] : string list *)
I want to write a function that taking a string and return a list of char. Here is a function, but I think it is not do what I want ( I want to take a string and return a list of characters).
let rec string_to_char_list s =
match s with
| "" -> []
| n -> string_to_char_list n
Aside, but very important:
Your code is obviously wrong because you have a recursive call for which all the parameters are the exact same one you got in. It is going to induce an infinite sequence of calls with the same values in, thus looping forever (a stack overflow won't happen in tail-rec position).
The code that does what you want would be:
let explode s =
let rec exp i l =
if i < 0 then l else exp (i - 1) (s.[i] :: l) in
exp (String.length s - 1) []
Source:
http://caml.inria.fr/pub/old_caml_site/FAQ/FAQ_EXPERT-eng.html#strings
Alternatively, you can choose to use a library: batteries String.to_list or extlib String.explode
Try this:
let explode s = List.init (String.length s) (String.get s)
Nice and simple:
let rec list_car ch =
match ch with
| "" -> []
| ch -> String.get ch 0 :: list_car (String.sub ch 1 (String.length ch - 1));;
How about something like this:
let string_to_list str =
let rec loop i limit =
if i = limit then []
else (String.get str i) :: (loop (i + 1) limit)
in
loop 0 (String.length str);;
let list_to_string s =
let rec loop s n =
match s with
[] -> String.make n '?'
| car :: cdr ->
let result = loop cdr (n + 1) in
String.set result n car;
result
in
loop s 0;;
As of OCaml 4.07 (released 2018), this can be straightforwardly accomplished with sequences.
let string_to_char_list s =
s |> String.to_seq |> List.of_seq
Here is an Iterative version to get a char list from a string:
let string_to_list s =
let l = ref [] in
for i = 0 to String.length s - 1 do
l := (!l) # [s.[i]]
done;
!l;;
My code, suitable for modern OCaml:
let charlist_of_string s =
let rec trav l i =
if i = l then [] else s.[i]::trav l (i+1)
in
trav (String.length s) 0;;
let rec string_of_charlist l =
match l with
[] -> ""
| h::t -> String.make 1 h ^ string_of_charlist t;;