Trouble with a the explode function SML - sml

I have a .txt file that contains this:
d3%~19^fgh54 78nm,.j
1.2k~789bv
This is the code that I have:
fun parse(L) =
let
val infile = TextIO.openIn(L)
fun read(infile) =
if TextIO.endOfStream(infile) then " " else (valOf(TextIO.inputLine(infile))) ^ read(infile);
fun split(S) = explode(S)
in
split(read(infile))
end;
This is the output I get:
[#"d",#"3",#"%",#"~",#"1",#"9",#"^",#"f",#"g",#"h",#"5",#"4",#" ",#"7",#"8",
#"n",...] : char list
I cannot figure out why the explode will not turn the whole string it is given into a char list.

The top-level printer in SML/NJ has limits for how much of data structures it prints.
You can adjust (among other things) the displayed length of lists and strings, and the depth of recursive structures with the Control.Print structure.
Example:
- Control.Print.printLength;
val it = ref 16 : int ref
- val stuff = [1,2,3,4,5,6,7,8,9,10];
val stuff = [1,2,3,4,5,6,7,8,9,10] : int list
- Control.Print.printLength := 4;
val it = () : unit
- stuff;
val it = [1,2,3,4,...] : int list
- Control.Print.printDepth;
val it = ref 5 : int ref
- val deep = [[[[[[[[]]]]]]]];
val deep = [[[[[#]]]]] : 'a list list list list list list list list
- Control.Print.printDepth := 10;
val it = () : unit
- deep;
val it = [[[[[[[[]]]]]]]] : 'a list list list list list list list list
If you want to see everything regardless of size, you need to define and use functions that print the way you like.

Related

Returning all elements from a Map[List()] in Scala

I'm VERY new to Scala so apologies if anything sounds a bit basic. Working on a uni assignment and can't seem to find any similar questions around.
EDIT: The idea of this function is that I pass through a string of data and separate it up into individual elements. From what I can tell, things are being separated correctly with the lists holding the correct data types and correct information.
So I've created a function that returns a Map[String, List[(Int, String, Float)]]
The function does other things, but to keep it short, once I've build the list this is how I build the map and return it: -
val newMap = Map(name -> newList2.toList)
newMap
I can newMap.foreach to cycle through the map and find all of my elements. This works as expected: -
(Sample Key,List((3,PlaceName1,2.7)))
(Sample Key,List((2,PlaceName1,3.8)))
(Sample Key,List((1,PlaceName1,0.75)))
I am simply trying to call this function and save the map into a new variable. I have tried this two ways: -
val saveMap = separator("1:PlaceName1:0.75,2:PlaceName2:3.8,3:PlaceName3:2.7")
However when I try to cycle through this, I only get the first list element: -
(Sample Key,List((1,PlaceName1,0.75)))
I have also tried to use a mapBuffer in the format of: -
var mapBuffer: Map[String, List[(Int, String, Float)]] = Map()
mapBuffer = separator("1:PlaceName1:0.75,2:PlaceName2:3.8,3:PlaceName3:2.7")
Again, all I get as my return here is: -
mutated mapBuffer
(Sample Key,List((1,PlaceName1,0.75)))
Being new to Scala but with some experience in Java and C#, it's killing me how I'm returning a Map value, saving it into a map value that is built the same, and it's not coming through. Tried every iteration of maps and lists I could find and can't find anything on this from searching.
Is anyone able to offer any assistance?
EDIT:
Here is the whole code for the function and how I am attempting to call it.
def separator(data:String): Map[String, List[(Int, String, Float)]] = {
//Route name will be worked out later. For now, this is a sample.
val sampleRouteName = "First Route"
//Stage list will hold each list entry
val stageList = ListBuffer[(Int, String, Float)]()
//Stage list builder will put all the list entries together
var stageListBuilder = List[(Int, String, Float)]()
if (data.contains(",")) {
//Find index of first comma
val commaIndex = data.indexOf(",")
//Split everything before the comma off
val (firstEntry, restOfPhrase) = data.splitAt(commaIndex)
//Find the index of the colon in the first entry
val colonIndex = firstEntry.indexOf(":")
//Split everything before the colon off to just keep the number
val (number, restOfStage) = firstEntry.splitAt(colonIndex)
//Get rid of the first colon from the rest of the line
val restOfStage2 = restOfStage.replaceFirst(":", "")
//Find the index of the next colon
val colonIndex2 = restOfStage2.indexOf(":")
//Split everything before the colon off to just keep the stage name
val (stageName, restOfStage3) = restOfStage2.splitAt(colonIndex2)
//Get rid of the colon leaving just the stage length
val stageLength = restOfStage3.replaceFirst(":", "")
//Put all of these together into a list line in the builder
stageListBuilder = List((number.toInt,stageName,stageLength.toFloat))
//Add the list line from the builder to the list as an element
stageListBuilder.foreach(line => stageList += line)
//Call recursive function and remove the comma from the start
separator(restOfPhrase.replaceFirst(",", ""))
}
else if (data.length != 0) {
//Find index of first colon
val colonIndex = data.indexOf(":")
//Split everything before the colon off to just keep the number
val (number, restOfStage) = data.splitAt(colonIndex)
//Get rid of the first colon from the rest of the line
val restOfStage2 = restOfStage.replaceFirst(":", "")
//Find the index of the next colon
val colonIndex2 = restOfStage2.indexOf(":")
//Split everything before the colon off to just keep the stage name
val (stageName, restOfStage3) = restOfStage2.splitAt(colonIndex2)
//Get rid of the colon leaving just the stage length
val stageLength = restOfStage3.replaceFirst(":", "")
//Put all of these together into a list line in the builder
stageListBuilder = List((number.toInt,stageName,stageLength.toFloat))
//Add the list line from the builder to the list as an element
stageListBuilder.foreach(line => stageList += line)
}
//This is a map that accurately contains the key (ie. GCU Route) and a list of the routes.
val routeMap = Map(sampleRouteName -> stageList.toList)
//To test that the list has all the elements (CURRENTLY WORKING)
routeMap.foreach(line => println("TEST - " + line))
//Return the map
routeMap
}
//val saveMap = separator("1:City Chambers:0.75,2:Velodrome:3.8,3:People's Palace:2.7")
//Create new map buffer
var mapBuffer: Map[String, List[(Int, String, Float)]] = Map()
//Call separator function
mapBuffer = separator("1:City Chambers:0.75,2:Velodrome:3.8,3:People's Palace:2.7")
//Test that each element is in the list (CURRENTLY NOT WORKING)
mapBuffer.foreach(line => println(line))
As you mentioned you are using same keys as a key of a Map. Let's imagine we have separator method like this:
val str = "1:PlaceName1:0.75,2:PlaceName2:3.8,3:PlaceName3:2.7"
def separator(str: String): List[(String, (Int, String, Float))] =
str.split(",").map(_.split(":")).toList.map(_.toList).collect {
case ii :: s :: d :: Nil =>
"Sample Key" -> (ii.toInt, s, d.toFloat)
}
separator(str).foearch(println)
// result:
(Sample Key,(1,PlaceName1,0.75))
(Sample Key,(2,PlaceName2,3.8))
(Sample Key,(3,PlaceName3,2.7))
if we convert our result to a Map we lose some elements with same key in this case Sample Key:
def separator1(str: String): Map[String, List[(Int, String, Float)]] =
str.split(",").map(_.split(":")).toList.map(_.toList).collect {
case ii :: s :: d :: Nil =>
"Sample Key" -> List((ii.toInt, s, d.toFloat))
}.toMap
separator1(str).foreach(println)
// result:
// (Sample Key,List((3,PlaceName3,2.7)))
So we cannot have the same keys as KEY of a Map. The KEYs of a Map should be a unique.
case class Aname(a: Int, b: String, c: Float)
def separator2(str: String): Map[String, List[Aname]] =
str.split(",").map(_.split(":")).toList.map(_.toList).collect {
case ii :: s :: d :: Nil =>
Aname(ii.toInt, s, d.toFloat)
}.groupBy(_.b)
separator2(str).foreach(println)
// result:
// (PlaceName3,List(Aname(3,PlaceName3,2.7)))
// (PlaceName2,List(Aname(2,PlaceName2,3.8)))
// (PlaceName1,List(Aname(1,PlaceName1,0.75)))
You can play with it here

insert an element into a sorted linked list

we had to implement the insert function that can insert a cell into a sorted linked list. My implementation idea was to have two rlists, called previous and current, that will be used to iterate through the list. At the beginning of the function call, the previous rlist will contain a random integer, and its next field is pointing to the current cell which is the head of the linked_list. I think this is problematic. I finished implementing my idea. I think the method will add the correct integer at the right place in the linked list. However, if the inserted element is at the beginning of the list, then the list is still the old list when using displaying on to the screen, but the old list does indeed have a cell pointing to it, and that cell has the inserted integer. So I'm not sure how to deal with that.
I tested my method, and it doesn't work as I described.
Here is what I did: I inserted -9 to the end of c3. c3 does indeed get -9 at the end of the list. And then I added 4 inside c5. But then c5 now becomes [5;4;-9]. So it is wrong, it should have [5;4;3;2;1;-9] instead. So I don't know what is wrong.
I looked up online on how to implement the method so that they can give me some inspirations or hint, but the solutions they provided are usually in Java or other programming languages.
type cell = { data : int; next : rlist}
and rlist = cell option ref
let c1 = {data = 1; next = ref None}
let c2 = {data = 2; next = ref (Some c1)}
let c3 = {data = 3; next = ref (Some c2)}
let c5 = {data = 5; next = ref (Some c3)}
let rec displayList (c : rlist) =
match !c with
| None -> []
| Some { data = d; next = l } -> d :: (displayList l)
let cell2rlist (c : cell) :rlist = ref (Some c)
let bigger((x:int), (y:int)) = (x > y)
let insert (comp : (int * int) -> bool) (item : int) (listt :rlist)=
let itemm = {data=item ; next = ref None} in
let rec helper (prev : rlist) (item : cell) (current: rlist) funcc =
match !current with
|None -> (match !prev with
|Some w -> w.next := (Some itemm))
|Some q -> if comp (item.data, q.data) then (itemm.next := (Some q) ; match !prev with
|Some w -> w.next := (Some itemm))
else prev := !current; current:= !(q.next); (helper prev item current funcc)
in let previous = ref (Some {data=0; next = listt}) in
helper previous itemm listt comp
Here are examples of the right return values for the code in action:
let l5 = cell2rlist c5;;
val l5 : rlist = ....
(* Messy display deleted. *)
displayList l5;;
- : int list = [5; 3; 2; 1]
displayList l5;;
- : int list = [5; 3; 2; 1]
insert bigger 4 l5;;
- : unit = ()
displayList l5;;
- : int list = [5; 4; 3; 2; 1]
insert bigger 9 l5;;
- : unit = ()
displayList l5;;
- : int list = [9; 5; 4; 3; 2; 1]
insert bigger 0 l5;;
- : unit = ()
displayList l5;;
- : int list = [9; 5; 4; 3; 2; 1; 0]
But when I ran my codes, here is what I get:
insert bigger 10 (ref(Some c5)) ;;
- : unit = ()
c5 ;;
- : cell =
{data = 5;
next =
{contents =
Some
{data = 3;
next =
{contents =
Some
{data = 2;
next = {contents = Some {data = 1; next = {contents = None}}}}}}}}
As you can see, if I insert a number that is supposed to be inserted at the beginning of the list, I can't see it.
Here is another example,
insert bigger 4 (ref(Some c5)) ;;
- : unit = ()
c5 ;;
- : cell =
{data = 5;
next =
{contents =
Some
{data = 4;
next = {contents = Some {data = 1; next = {contents = None}}}}}}
So as you see the code doesn't work at all as the updated list should have values [5;4;3;2;1] but it has [5;4;1] instead.
Here is another example:
insert bigger (-9) (ref(Some c3)) ;;
- : unit = ()
c3 ;;
- : cell =
{data = 3;
next =
{contents =
Some
{data = 2;
next =
{contents =
Some
{data = 1;
next = {contents = Some {data = -9; next = {contents = None}}}}}}}}
So it seems that the method does insert the element correctly into the list, but the lists that the inserted cell suppose to point to seem to be wrong.
For reference, here is a session showing a failure of your code:
# let (l: rlist) = ref None;;
val l : rlist = {contents = None}
# insert bigger 1 l;;
- : unit = ()
# l;;
- : rlist = {contents = Some {data = 1; next = {contents = None}}}
# insert bigger 0 l;;
- : unit = ()
# l;;
- : rlist = {contents = None}
For what it's worth, it would also be good if your code was indented properly.
At any rate, what I see when I look at your code for a short time is this fragment:
current:= !(q.next);
helper prev item current funcc
It looks to me like you're imagining that the first line here will advance some local variable to point to the next element of the list. But what it actually is doing is modifying the list.
You might want something more like this:
helper prev item q.next funcc
There are other problems in your code as well. It seems odd, for example, that the then part is parenthesized but the else part isn't parenthesized.

Extracting values from a function via matching

I'm working on an assignment and was given the following function:
fun label (lb,ub) =
let val s = callcc (fn k =>let fun branch c = if (c < ub)
then (pushCP (k,branch,c+1);c)
else ub
in (pushCP(k,branch,lb+1);lb)
end)
in {value=s,dom=(lb,ub)}
end;
If you put a lower and upper bound of let's say 1 and 3into this function it would print
val it = {dom=(1,3), value=1}
What I am trying to figure out is if it is at all possible to get the value. In my notes it says two possible ways of doing this would be through #value(x) or by doing val {value=a,...} = x, but I get errors both ways with this.
Any clue what I am doing wrong?
It isn't clear what you are doing wrong since you haven't reproduced what you actually tried, but your notes are correct:
- val x = {dom=(1,3), value=1};
val x = {dom=(1,3),value=1} : {dom:int * int, value:int}
The first method is to use #value to extract the value field and #dom to extract the dom field:
- #value x;
val it = 1 : int
- #dom x;
val it = (1,3) : int * int
The second method is to use pattern matching. You can extract individual fields:
- val {value = a,...} = x;
val a = 1 : int
Or you can extract both fields at once:
- val {dom = a, value = b} = x;
val a = (1,3) : int * int
val b = 1 : int
In order for the above to work, x needs to be bound to the value. Perhaps you are trying to use this with an x which hasn't been given a val binding. You would need to have something like this:
val x = label(1,3)
I don't have all the relevant code so I can't test. If the above isn't enough to answer your question, you need to provide more details.

Joining two lists with common elements - Scala

I have 2 Lists as mentioned below:
val L1 = List[(Int,Int,String)]
val L2 = List[(Int,Int,String)]
I want to join these 2 lists on the basis of 1st and 2nd Int element in a way that result list must have 4 elements (Int,Int,String,String).
val joinedList = List[(Int, Int, String, String)]
where last 2 String elements will be string from L1 and string from L2.
Ex:-
val L1 = List((1,1,"one"), (2,2,"two"))
val L2 = List((2,2,"twice"), (3,3,"thrice"))
Output List ->
val joinedList = List((1,1,"one","--"),(2,2,"two","twice"), (3,3,"--","thrice"))
Kindly suggest a way to achieve that in scala.
First you want to get it into Maps, so it's easier to look up, then you can just map over all the keys:
val L1Map = L1.map{case (x,y,z) => ((x,y) -> z)}.toMap
val L2Map = L2.map{case (x,y,z) => ((x,y) -> z)}.toMap
val allKeys = L1Map.keySet ++ L2Map.keySet
val result = allKeys map {case (x,y) =>
(x, y, L1Map.getOrElse((x,y), "--"), L2Map.getOrElse((x,y), "--"))
}
That gives you an unsorted Set as a result. If you need a List, you can convert it back and sort it as necessary.

Function that takes type unit

I'm trying to create a function that has the type:
unit -> (int list * int list * int list)
But I was wondering, unit is an empty type (has no value), so how would it be possible to do something with it and return 3 int lists?
Thanks
The type unit is not empty.
It has one value which is spelled () and is usually called "unit", like its type.
(One meaning of the word "unit" is "a single thing".)
Example:
- ();
val it = () : unit
- val you_knit = ();
val you_knit = () : unit
- fun foo () = ([1], [2], [3]);
val foo = fn : unit -> int list * int list * int list
- foo ();
val it = ([1],[2],[3]) : int list * int list * int list
- foo you_knit;
val it = ([1],[2],[3]) : int list * int list * int list
(Note that () is not an empty parameter list; ML doesn't have parameter lists.)
Strictly speaking, the above definition pattern-matches on the value ().
Without pattern matching, it could look like this:
- fun bar (x : unit) = ([1], [2], [3]);
val bar = fn : unit -> int list * int list * int list
- bar ();
val it = ([1],[2],[3]) : int list * int list * int list
In SML type unit often represents an input/output action or more generally something which involves side effects. A somewhat realistic example of a function of the sort you are looking for would be one which returns 3 randomly generated lists. Another example would be one which pulls numbers from standard input something like:
open TextIO
fun split s = String.tokens (fn c => c = #",") s
fun toInt s = valOf (Int.fromString s)
fun toIntList line = map toInt (split line)
fun getInts prompt =
(
print prompt;
case inputLine(stdIn) of
SOME line => toIntList line |
NONE => []
)
fun getLists() =
let
val prompt = "Enter integers, separated by a comma: "
in
(getInts prompt, getInts prompt, getInts prompt)
end
The type of getLists is
val getLists = fn : unit -> int list * int list * int list
a typical "run" of getLists:
- getLists();
Enter integers, separated by a comma: 1,2,3
Enter integers, separated by a comma: 4,5,6
Enter integers, separated by a comma: 7,8,9
val it = ([1,2,3],[4,5,6],[7,8,9]) : int list * int list * int list