I'm new to SML and in debugging I usually print out the variable to see if it matches up to what I expected it should be.
I would like to print out a variable within a function
what i have is this :
function header..
let val prod
val prod = c + x * y;
in
(print "product "; prod mod 10):: (multiplyAux (prod div 10) xs y)
end;
Right now its printing the string product, but I would like to be able to print the variable prod itself.
The only thing that print can print is strings. So to print a numeric value, it must first be converted to a string. For example:
- print("product " ^ (Int.toString (43 mod 5)) ^ "\n");
product 3
val it = () : unit
Note that Int.toString uses the curried function syntax (i.e. it does not require a tuple for it's argument) so the parenthesis around 43 mod 5 are to make the value clear not to make Int.toString work.
- Int.toString 5;
val it = "5" : string
Related
I am new in sml. I tried to convert int to int list. For example, assume that there is an input 1234, then output is a list like [1,2,3,4]. And my question is, how can I type nested functions in sml? let in end? There is my code.
fun digit (a : int): int =
let
fun size (a) = if a < 0 then nil
else x = Int.toString x then digit s = size(x)
fun insert (num, nil) = [num]
| insert (num,xs) = x :: insert ()
fun convert (a, s) = if s < 0 then nil
else insert (a / (10*(s - 1)), xs)
then convert(a - (10*(s - 1), s - 1)
in
end
Nested functions are just one way to split up your workload in multiple, smaller parts. Another option is non-nested library functions. The main differences are that functions that aren't nested don't inherit its parent's variable scope, so they can only work with their own input, and functions that are nested aren't available anywhere else and can't be re-used. Let's say you're giving this problem a first stab:
fun digit_meh n = if n < 10 then [n] else n mod 10 :: digit_meh (n div 10)
And you realize it isn't doing exactly as you want:
- digit_meh 1234;
> val it = [4, 3, 2, 1] : int list
You could remove the most significant digit first, but the calculation isn't as trivial as n mod 10, since it depends on the number of digits.
You could generate this list and then reverse it:
fun digit n = rev (digit_meh n)
But the function digit_meh isn't particularly useful outside of this function, so it could be hidden using local-in-end or let-in-end:
local
fun digit_meh n = if n < 10 then [n] else n mod 10 :: digit_meh (n div 10)
in
val digit = rev o digit_meh
end
fun digit n =
let fun meh n = if n < 10 then [n] else n mod 10 :: meh (n div 10)
in rev (meh n) end
Do notice that the function meh's copy of n shadows digit's copy of n.
For clarity you could also name the variables differently.
Or you could look at how rev is doing its thing and do that. It basically treats its input as a stack and puts the top element in a new stack recursively so that the top becomes the bottom, much like StackOverflow's logo would look like if it jumped out and landed upside down like a slinky spring:
fun rev L =
let fun rev_stack [] result = result
| rev_stack (x::xs) result = rev_stack xs (x::result)
in rev_stack L [] end
Because the result is accumulated in an additional argument, and rev should only take a single argument, nesting a function with an extra accumulating argument is a really useful trick.
You can mimic this behavior, too:
fun digit N =
let fun digit_stack n result =
if n < 10
then n::result
else digit_stack (n div 10) (n mod 10::result)
in f N [] end
This way, we continue to treat the least significant digit first, but we put it in the stack result which means it ends up at the bottom / end. So we don't need to call rev and save that iteration of the list.
In practice, you don't have to hide helper functions using either local-in-end or let-in-end; while it can be useful in the case of let-in-end to inherit a parent function's scope, it is not necessary to hide your functions once you start using modules with opaque signatures (the :> operator):
signature DIGIT =
sig
val digit : int -> int list
end
structure Digit :> DIGIT =
struct
fun digit_stack n result =
if n < 10
then n::result
else digit_stack (n div 10) (n mod 10::result)
fun digit n = digit_stack n []
end
As this is entered into a REPL, only the relevant function is available outside of the module:
> structure Digit : {val digit : int -> int list}
signature DIGIT = {val digit : int -> int list}
- Digit.digit 1234;
> val it = [1, 2, 3, 4] : int list
fun aFunctionCallingF2F3 someVariables =
let
<define some functions and local variables here>
fun F2 ...
fun F3 ...
val v1 ...
val v2 ...
in
<Make use of the functions/variables you defined above and `someVariables`>
end
For example,
fun areaCirle r:real =
let fun square x:real = x*x
val pi = 3.14
in
pi * square r
end
Or define functions you need to call beforehand if they are not mutually recursive. If they are mutually recursive, you can look up the keyword and.
fun F2 ...
fun F3 ...
fun aFunctionCallingF2F3 = <make use of F2 F3 directly>
For example,
fun square x:real = x * x
fun areaCircle r = square r * 3.14
Note that you cannot do
fun areaCircle r = square r * 3.14
fun square x:real = x * x
square needs to be defined before areaCircle.
I did "mkString" but still can not print list of strings. With input line:
9002194187,2644,54,100,3,4,2,5
I get the following output:
Line: 9002194187,2644,54,100,3,4,2,5
StrArr: 9002194187,2644,54,100,3,4,2,5
Lst: [Ljava.lang.String;#223d2e6c
Lst again: List([Ljava.lang.String;#223d2e6c)
Lst1: [Ljava.lang.String;#223d2e6c
Result: foo
From the code below:
def mkRecord(line: String) : String = {
val klass = "foo"
val strArr = line.split(",") // convert string to array of strings
println("Line: "+line)
println("StrArr: "+strArr.mkString(","))
val lst = List(strArr)
println("Lst: "+lst.mkString(" - "))
println("Lst again: "+lst)
val lst1 = lst.tail ++ List(klass) // attribute list except for the first one, plus new klass attribute
println("Lst1: "+lst.mkString(" , "))
val result = lst1.mkString(",") // attribute string
println("Result: "+ result)
return result
}
Please, help. I am at complete loss (
The constructor for List (actually, the apply method on the List companion object) takes parameters in the form of scala's "varargs" equivalent:
def apply[A](xs: A*): List[A] // some irrelevant details have been elided
In java, this would be written something like:
public static List<A> apply(A... args)
In scala this can be called using any Seq (or subclass), but using a special notation. The line you used:
val lst = List(strArr)
creates a List[Array[String]], with a single entry - the array strArr. To tell the compiler to turn the array into a varargs when passing it to the List apply method, add : _* on the end (the space is optional):
val lst = List(strArr: _*)
This change in your code will result in:
scala> mkRecord(chkStr)
Line: 9002194187,2644,54,100,3,4,2,5
StrArr: 9002194187,2644,54,100,3,4,2,5
Lst: 9002194187 - 2644 - 54 - 100 - 3 - 4 - 2 - 5
Lst again: List(9002194187, 2644, 54, 100, 3, 4, 2, 5)
Lst1: 9002194187 , 2644 , 54 , 100 , 3 , 4 , 2 , 5
Result: 2644,54,100,3,4,2,5,foo
res1: String = 2644,54,100,3,4,2,5,foo
You can turn any array into a list with its toList operator, avoiding this problem (the nature of which Shadowlands has explained). You can do string -> array -> list in one line:
line.split(',').toList
Using a collection's toList method is often going to be faster than extracting all the elements into a sequence and then converting that sequence into a list, not least because you'll be using a method optimised for the source collection. However, that's an optimisation which you can worry about after the priorities of success and clarity.
I'm having a problem while trying to increment my value of x inside the inner foldl call. I make x equal to shiftValue that's passed in and attempt to increment it whenever I find a #" " or #"*" in the inner foldl call, but the value of x that gets returned is always the same as shiftvalue was when passed in.
The function takes in a tuple of (string, int) where the string will have leading spaces and asterisk chopped off that come before any other characters. Also any spaces or asterisk on the end not followed by any other characters will get chopped off. The int that is passed in is a shiftValue that tracks how many spaces the string was shifted over before getting passed into this function. Whenever I take off a leading space or asterisk I need to increment the shiftValue "x" by one.
The inner foldl call removes asterisks and spaces from the front. The outer foldl call removes them from the back. The asterisks and spaces get removed right, the x value just isn't getting updated.
(*Take string str and get rid of leading and following #"*"s and #" "s. For every
leading #"*" or #" " removed increment the shiftValue returned in the tuple*)
fun trimStarsOnNode (str, shiftValue) =
let
val x = shiftValue
in
((implode(rev (foldl (fn (cur, a) =>
if length a = 0 andalso cur = #"*" then a # []
else
if length a = 0 andalso cur = #" " then a # []
else a # [cur]) [] (rev (foldl (fn (cur, a) =>
if length a = 0 andalso cur = #"*" then (x = x + 1; a # [])
else
if length a = 0 andalso cur = #" " then (x = x + 1; a # [])
else a # [cur]) [] (explode str)))))), x)
end;
trimStarsOnNode ("***hello", 3); (* Should print out ("hello", 6) *) but prints out ("hello", 3)
Look at your x - in the beginning of your function, you do:
val x = shiftValue
Then, later, you try to do this:
x = x + 1
Remember, in SML, you can't change the value of a variable (actually, they're just called values in SML, for that reason). x = x + 1 just compares x and x + 1, so the value of the statement x = x + 1 is boolean false.
As Tayacan says, variables are not mutable in SML. If you want mutability you need to use reference types -- but usually, they are best avoided and it's preferable to stick to functional style.
It's also worth noting that your function is going to be very inefficient (O(n^2)), because of your use of list concatenation and length on every iteration. And it is incorrect, because it will also remove stars in the middle of the string (and then redundantly go over the whole list a second time). Finally, your solution is far too complicated.
FWIW, here is the shortest implementation I can think of, using the Substring library module and the function composition operator o:
fun isStarOrSpace c = (c = #"*" orelse c = #" ")
val trimStars =
let open Substring
in string o dropl isStarOrSpace o dropr isStarOrSpace o full end
This does not use your shiftValue because I don't understand what it's supposed to do. You can easily compute the number of removed characters by comparing the old and new string size. That is, your intended function (IIUC) could easily be expressed on top of mine as
fun trimStarsOnNode(s, shift) =
let val s' = trimStars s in (s', size s - size s' + shift) end
But to be honest, I don't understand what this version would be good for.
Edit: A version that returns the left drop count:
fun trimStars s =
let
open Substring
val ss = dropl isStarOrSpace (dropr isStarOrSpace (full s))
in
(string ss, #2(base ss))
end
Would someone please explain why the code below,
let list = ["A"; "B"; "C"]
let rec processList2 aList str =
match aList with
| h::t -> let z = str + ", " + h
printfn "%s" z
processList2 t z
| [] -> aList |> ignore
returns the following,
val list : string list = ["A"; "B"; "C"]
> processList2 list "X";;
X, A
X, A, B
X, A, B, C
val it : unit = ()
>
instead of this?
val list : string list = ["A"; "B"; "C"]
> processList2 list "X";;
X, A
X, A, X, B
X, A, X, B, X, C
val it : unit = ()
>
The function is recursive and passes 'z' to 'str' with each pass, so it seems like it should work...
I really appreciate the experts' help here. I am trying to learn F# and struggling with lists.
Also, how does one declare a 'list of strings?' I had an issue where a list expected to return a unit instead of a string.
If we follow along with each step it should help us understand why you get the result you get:
processList2 list "X";;
The first iteration takes h::t or "A"::["B"; "C"]. It then sets z to "X" + ", " + "A".
The next iteration takes "B"::["C"]. It then sets z to "X, A" + ", " + "B".
As you can see "X" does not get inserted in each iteration. Rather z gets appended to and set through each iteration building on the last. To append "X" at each iteration it would need to be something like:
let list = ["A"; "B"; "C"]
// Append "X, " to each item
let mapList item = "X, " + item
// reduce to single comma seperated list
let redList l r = l + ", " + r
// apply map and reduce functions to given list
let result = list |> List.map(mapList) |> List.reduce(redList)
printfn "%s" result
If you wanted you could even use String.Join to reduce the list however that requires a few more hoops to jump through:
let list = ["A"; "B"; "C"]
let mapList item = "X, " + item
let joinList (lst:list<string>) = System.String.Join(", ", lst)
let result = list |> List.map(mapList) |> joinList
printfn "%s" result
As for you last question: how does one declare a 'list of strings?, the answer depends on what you mean by declare. Are you trying to declare a variable of that type or a parameter that accepts it?
Declaring a variable as a certain type if generally done like this: let lst:string list = ["A"; "B"; "C"] where the type is given after the : during the declaration. If it is in a parameter than you have to be a little more explicit as you have to tell the compiler that you are setting the parameters type and not the return type:
// Set the lst parameter type to be a list<string> (same as string list)
let joinList (lst:list<string>) = System.String.Join(", ", lst)
// fails as we are telling the compiler to expect a return of string list yet we are only returning string
let joinList lst:list<string> = System.String.Join(", ", lst)
// Explicitly set both return and parameters
let joinList (lst:string list):string = System.String.Join(", ", lst)
Typically this wont be required as the type inference system in F# is very good and figuring out what type you want/need in these situations.
Given this following code (which does not work):
fun func() =
val decimal = 0 (* the final result *)
val multiple = 0 (* keeps track of multiples, eg. In XXV, X would be a multiple *)
val current = 0 (* the digit currently being processed *)
val top = 0 (* value of the last element in the list *)
val last_add = 0 (* the last digit that wasn't a multiple, or subtraction operation *)
val last_sub = 0
val problem = 0 (* if value is 1 then there is a problem with the input *)
val myList = [1,2,3,4,5] (* the list has more values *)
val current = tl(myList) (* grab the last element from the list *)
val myList = tl(myList) (* remove the last element from the list *)
val top = tl(myList) (* grab the value at the end of the list *)
while (not(myList = [])) (* run while the list is not empty *)
if ( (not(myList = [])) andalso (current > top))
then
val decimal = decimal + current - top
val last_sub = top;
val myList = tl(myList)
else
if ( (myList = []) andalso (current = top))
then val decimal = decimal + current
val multiple = multiple + 1
else
if (last_sub = current)
then val problem = 1
else
val decimal = decimal + current
val multiple = 0
val last_add = current
This is only a partial code , which doesn't work at the moment , since the val is not
possible within an if statement .
I want to run in a while loop , how can I do that in ML ?
How can I assign and reassign values into variables that were previously declared in ML ?
The val keyword is not possible within the IF condition , so I cannot update the variables , any idea how to solve that ?
Regards
How can I assign and reassign values into variables that were
previously declared in ML ?
You cannot assign to variables after they are declared in ML.
The val keyword is not possible within the IF condition , so I cannot
update the variables , any idea how to solve that ?
Except at the top level, you usually use val and fun inside a let:
let
val x = blah blah
val y = blah blah
fun f x y = blah blah
in
some expression
end
However, note that this creates a new variable (which may hide any existing variable of the same name), which exists inside the scope of the body of the let. As said before, you cannot assign to an existing variable.
I want to run in a while loop , how can I do that in ML ?
You are almost there. The syntax is while condition do ( ... ). But a while loop is useless without mutable state.
If you want mutable state, you can use a mutable data structure. The language provides a simple "mutable cell" called ref: you create it by passing the initial value to the ref function, you get the current value with the ! operator, and you set a new value with the := operator. You also have to remember that if you want to run multiple imperative "statements", you must separate them with the ; operator, and possibly enclose the whole "block" of statements in parentheses due to precedence issues.
But using while loops and mutable state is really not the right way to go here. You are using a functional language, and it would be much better for you to re-write your algorithm to be purely functional. It's not hard to do. You would turn the body of your while loop into a tail-recursive helper function, and the "variables" that change between iterations of the loop would become arguments to this function. Instead of trying to "set" the values of these variables, it would simply recursively call itself with the new values for the next iteration. If it's tail-recursive, it's equivalent to iteration memory-wise.