14 Replies - 1520 Views - Last Post: 29 October 2015 - 03:27 PM

#1 rshah  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 37
  • Joined: 21-October 15

Trying to get first word from character list in SML (SMLNJ)

Posted 25 October 2015 - 09:34 AM

Hey guys!

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:

Quote

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;



Can anybody help me with this solution? Thanks!

Is This A Good Question/Topic? 0
  • +

Replies To: Trying to get first word from character list in SML (SMLNJ)

#2 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon


Reputation: 6997
  • View blog
  • Posts: 14,636
  • Joined: 16-October 07

Re: Trying to get first word from character list in SML (SMLNJ)

Posted 25 October 2015 - 03:21 PM

Ok, I don't know Standard ML, but I know a few of its relatives, so I'll have a go here.

First, I couldn't really get your code to compile. I don't think the end should be there and I don't understand the syntax that well. So, I broke out your functions into smaller ones and cleaned up a little, getting this:
fun isLower x = ord(x) >= 97 andalso ord(x) <= 122;

fun getword [] = []
    | getword (x::tl) = if(isLower x) then [x]@getword tl else [];

fun next [] = ([], [])
   | next (x::tl) =
     if(not(isLower x))
      then ([], (x::tl))
      else next (getword (x::tl));

val msg = [#"h", #"i", #" ", #"h", #"i"];



In parser:
Standard ML of New Jersey v110.76 [built: Wed Oct 23 00:32:24 2013]
[opening t.sml]
val isLower = fn : char -> bool
val getword = fn : char list -> char list
val next = fn : char list -> 'a list * char list
val msg = [#"h",#"i",#" ",#"h",#"i"] : char list
- getword msg;
val it = [#"h",#"i"] : char list
- next msg;
stdIn:1.2-1.10 Warning: type vars not generalized because of
   value restriction are instantiated to dummy types (X1,X2,...)



And off next went into an infinite loop. Note the sig of next (char list -> 'a list * char list). It's not a good sign that it doesn't know the first list type.

I'd start with a simpler function. Recall, this is functional programmer; many small functions are better than one big one.

I wrote something called firstword:
Standard ML of New Jersey v110.76 [built: Wed Oct 23 00:32:24 2013]
[opening t.sml]
val isLower = fn : char -> bool
val getword = fn : char list -> char list
val firstword = fn : char list -> char list -> char list * char list
val next = fn : char list -> 'a list * char list
val msg = [#"h",#"i",#" ",#"h",#"i"] : char list
- firstword [] msg;
val it = ([#"h",#"i"],[#" ",#"h",#"i"]) : char list * char list
-



Perhaps firstword is you next? Not sure.

Note how for firstword I had to give it empty list to start. I found it easier to start with an accumulator, so it begins as:
fun firstword acc [] = (acc, [])
  | firstword acc (x::t) =



Hope this helps.
Was This Post Helpful? 2
  • +
  • -

#3 rshah  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 37
  • Joined: 21-October 15

Re: Trying to get first word from character list in SML (SMLNJ)

Posted 26 October 2015 - 01:56 AM

Yeah! Your firstword method does work the way i want it too. Here is how i managed to do it in the end:

fun next [] = ([], [])
   | next list =
     let
       fun isLegal c = ord c >= 97 andalso ord c <= 122;
       fun getword (hd::tl) word =
         if isLegal hd
         then getword tl (hd::word)
         else (rev word, hd::tl)
       | getword [] word = (rev word, [])
     in
       getword list []
     end;



Thanks for the help in the end though!
Was This Post Helpful? 1
  • +
  • -

#4 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon


Reputation: 6997
  • View blog
  • Posts: 14,636
  • Joined: 16-October 07

Re: Trying to get first word from character list in SML (SMLNJ)

Posted 26 October 2015 - 06:31 AM

Excellent. I'm glad you got it.

Note that if you put isLegal outside, you can generalize your splitter by passing a function.
Was This Post Helpful? 0
  • +
  • -

#5 rshah  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 37
  • Joined: 21-October 15

Re: Trying to get first word from character list in SML (SMLNJ)

Posted 26 October 2015 - 07:47 AM

View Postbaavgai, on 26 October 2015 - 06:31 AM, said:

Excellent. I'm glad you got it.

Note that if you put isLegal outside, you can generalize your splitter by passing a function.


Yeah but i only need it for this function so its alright ^^ I have another issue though sadly with another similar function:

I have a function 'incCount' which increments a counter in for every indentical element in a tuple list. For example:

incCount "the" [("the", 1), ("hi", 1)] => [("the", 2), ("hi", 1)]



And using this function, I have a list of words
["the", "what", "hi", "hello"];


Which i have to create the incCount list using those words!

Here is my incCount function:

fun incCount w [] = [(w, 1)] |
    incCount w ((hd, n)::tl) =
        if w = hd
        then (hd, n+1)::tl
        else (hd, n)::(incCount w tl);


Was This Post Helpful? 0
  • +
  • -

#6 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon


Reputation: 6997
  • View blog
  • Posts: 14,636
  • Joined: 16-October 07

Re: Trying to get first word from character list in SML (SMLNJ)

Posted 26 October 2015 - 08:54 AM

This is significantly easier than the incCount function is. You are just iterating over the list. A fold would be good for this.

It's only a one liner. However, if it helps, this is how the function would work:
countWords ["the","what","hi","hello"]
  countWords ["what","hi","hello"]
    countWords ["hi","hello"]
      countWords ["hello"]
        countWords []
        return []
      return [("hello",1)]
    return [("hello",1),("hi",1)]
  return [("hello",1),("hi",1),("what",1)]
return [("hello",1),("hi",1),("what",1),("the",1)]



Hope this helps.
Was This Post Helpful? 0
  • +
  • -

#7 rshah  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 37
  • Joined: 21-October 15

Re: Trying to get first word from character list in SML (SMLNJ)

Posted 28 October 2015 - 06:59 AM

View Postbaavgai, on 26 October 2015 - 08:54 AM, said:

This is significantly easier than the incCount function is. You are just iterating over the list. A fold would be good for this.

It's only a one liner. However, if it helps, this is how the function would work:
countWords ["the","what","hi","hello"]
  countWords ["what","hi","hello"]
    countWords ["hi","hello"]
      countWords ["hello"]
        countWords []
        return []
      return [("hello",1)]
    return [("hello",1),("hi",1)]
  return [("hello",1),("hi",1),("what",1)]
return [("hello",1),("hi",1),("what",1),("the",1)]



Hope this helps.


I tried this and here is my output as well:

fun countWords [] [] = []
   | countWords [] l = l
   | countWords [w] [] = [(w, 1)]
   | countWords (hd::tl) l =
       (incCount hd l)@countWords tl l;
- val countWords = fn : ''a list -> (''a * int) list -> (''a * int) list

countWords ["the", "hi", "hello", "hi"] [];
- val it = [("the",1),("hi",1),("hello",1),("hi",1)] : (string * int) list



You can see that it doesn't increment the value in the output if it already exists like the function should do.
Was This Post Helpful? 0
  • +
  • -

#8 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon


Reputation: 6997
  • View blog
  • Posts: 14,636
  • Joined: 16-October 07

Re: Trying to get first word from character list in SML (SMLNJ)

Posted 28 October 2015 - 07:57 AM

Hmm... you never use l.
Trace it again:
countWords ["the", "hi", "hello", "hi"] []
 -> (incCount "the" []) @ countWords ["hi", "hello", "hi"] []

countWords ["hi", "hello", "hi"] []
 -> (incCount "hi" []) @ countWords ["hello", "hi"] []



You're always doing your incCount on an empty list. Try doing your incCount on the results of the prior call. You don't need to pass l. You also only need two cases.
Was This Post Helpful? 0
  • +
  • -

#9 rshah  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 37
  • Joined: 21-October 15

Re: Trying to get first word from character list in SML (SMLNJ)

Posted 28 October 2015 - 08:53 AM

View Postbaavgai, on 28 October 2015 - 07:57 AM, said:

Hmm... you never use l.
Trace it again:
countWords ["the", "hi", "hello", "hi"] []
 -> (incCount "the" []) @ countWords ["hi", "hello", "hi"] []

countWords ["hi", "hello", "hi"] []
 -> (incCount "hi" []) @ countWords ["hello", "hi"] []



You're always doing your incCount on an empty list. Try doing your incCount on the results of the prior call. You don't need to pass l. You also only need two cases.


I still can't seem to figure out why im calling it on the empty list :online2long:
Was This Post Helpful? 0
  • +
  • -

#10 rshah  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 37
  • Joined: 21-October 15

Re: Trying to get first word from character list in SML (SMLNJ)

Posted 28 October 2015 - 09:00 AM

baavgai I tried this but I'm getting a circularity error:

fun countWords [] = [(nil, nil)]
   | countWords (hd::tl) =
       (incCount hd tl)@countWords tl;

stdIn:120.3-120.17 Error: operator and operand don't agree [circularity]
  operator domain: (''Z * int) list
  operand:         ''Z list
  in expression:
    (incCount hd) tl


Was This Post Helpful? 0
  • +
  • -

#11 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon


Reputation: 6997
  • View blog
  • Posts: 14,636
  • Joined: 16-October 07

Re: Trying to get first word from character list in SML (SMLNJ)

Posted 28 October 2015 - 09:26 AM

Ah, you've totally confused your type inference.

See, incCount will get defined as:
val incCount = fn : ''a -> (''a * int) list -> (''a * int) list



That means, the first value will be a thing, and the next will be a list of type thing, int.

This makes your call incCount hd tl impossible, as hd is a thing and tl is a list of thing, not thing, int.

In any case, it's wrong but you're closing in. Big hint, you wont need that @.
Was This Post Helpful? 0
  • +
  • -

#12 rshah  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 37
  • Joined: 21-October 15

Re: Trying to get first word from character list in SML (SMLNJ)

Posted 29 October 2015 - 01:38 AM

View Postbaavgai, on 28 October 2015 - 09:26 AM, said:

Ah, you've totally confused your type inference.

See, incCount will get defined as:
val incCount = fn : ''a -> (''a * int) list -> (''a * int) list



That means, the first value will be a thing, and the next will be a list of type thing, int.

This makes your call incCount hd tl impossible, as hd is a thing and tl is a list of thing, not thing, int.

In any case, it's wrong but you're closing in. Big hint, you wont need that @.


I've never been this confused haha! Im trying to figure out what I could do to replace 'tl' for something of type (''a * int) list instead of (''a list).
Was This Post Helpful? 0
  • +
  • -

#13 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon


Reputation: 6997
  • View blog
  • Posts: 14,636
  • Joined: 16-October 07

Re: Trying to get first word from character list in SML (SMLNJ)

Posted 29 October 2015 - 03:31 AM

The above can be confusing. However, until you actually understand that, this stuff will only get harder. For now, ignore it and think about your problem.

The answer to this is simpler than what you're doing and you're close. If you more enough symbols around, you'll find it. However, it's more important that you understand it.

Take another look at my recursion mapping. For your list ["the", "hi", "hello", "hi"], the result looks like:
return []
return [("hi",1)]
return [("hi",1),("hello",1)]
return [("hi",2),("hello",1)]
return [("hi",2),("hello",1),("the",1)]



Again, if you could write incCount, this should be easier.

Good luck.
Was This Post Helpful? 0
  • +
  • -

#14 rshah  Icon User is offline

  • New D.I.C Head

Reputation: 2
  • View blog
  • Posts: 37
  • Joined: 21-October 15

Re: Trying to get first word from character list in SML (SMLNJ)

Posted 29 October 2015 - 04:12 AM

Figured it out!

Thanks hahaha

fun countWords [] = []
   | countWords [w] = [(w, 1)]
   | countWords (hd::tl) = incCount hd (countWords tl);


Was This Post Helpful? 0
  • +
  • -

#15 baavgai  Icon User is offline

  • Dreaming Coder
  • member icon


Reputation: 6997
  • View blog
  • Posts: 14,636
  • Joined: 16-October 07

Re: Trying to get first word from character list in SML (SMLNJ)

Posted 29 October 2015 - 03:27 PM

Excellent.

Note, you don't need that second line. It will run fine as:
fun countWords [] = []
   | countWords (hd::tl) = incCount hd (countWords tl);


Was This Post Helpful? 1
  • +
  • -

Page 1 of 1