Replies: 13 comments
-
|
The type system is your friend. Here is your problem (or rather the problem with the
book solution).
$ legacy/bin/sml
Standard ML of New Jersey (64-bit) v110.99.4 [built: Thu Feb 08 17:49:14 2024]
- chr;
val it = fn : int -> char
- ord;
val it = fn : char -> int
- op ^;
val it = fn : string * string -> string
- substring;
val it = fn : string * int * int -> string
- sub;
val it = fn: string * int -> char
- Char.toString;
val it = fn : char -> string
s: string ==> "ord s” fails to type check
The function ord wants a char argument and is passed a string. sub (s, 0) will give you the first character in the string s, which is what the solution seems to want. Then you have a character, to which you can apply the ord function (Char.ord) to get a number (e.g. ord #”a” => 97).
As above, you can use the interactive system to query the type of a function, or you can look them up in the SML Basis documentation (https://smlfamily.github.io/Basis/). The relevant operations here come from Basis structures Char and String, which have signatures CHAR and STRING documented in the Basis library (because it is possible to have more than one implementation of the CHAR signature, e.g. Latin1 or Unicode that provide different numbers of characters with different sized representations.)
Given that s is of type string and the string concatenation operator “^” operates on two strings, the first (left) argument of the concatenation probably should be
Char.toString (chr (ord (sub(s,0)) + 1))
instead of
chr (ord s + 1)
and the function definition should be
fun incFirst (s: string) =
Char.toString (chr (ord (sub(s,0)) + 1)) ^ substring (s, 1, size s - 1)
where the "substring (s, 1, size s - 1)" expression could be replaced by the equivalent
expression "extract (s, 1, NONE)" (see Basis documentation for signature STRING).
To summarize, you need to pay attention to the types of variables (like “s”) and the operations that are applied to them, and make sure that they are compatible. You also need to learn the “API”s associated with characters and strings (in this case the Basis structures (i.e., modules) Char and String) which provide ways to transform values from one type to another (e.g. String.sub, Char.ord, Char.chr, Char.toString) that here allow one to go from strings to characters to ints and back again.
In this case, most of the functions you need (like “chr”, “ord”, “sub”, “^”) happen to be available at “top level”, but not all (e.g.. Char.toString). This means you need to become familiar with the contents of Basis library structures like Char and String (or rather, in this case, their signatures CHAR and STRING). The set of function names that are deemed useful or important enough to be available directly in the top level environment is somewhat arbitrary, and their meanings might not be what you expect. For instance, there is a toString function defined at top level, but its value is the function String.toString of type “string -> string” which is not the same as the Char.toString function of type "char -> string”.
Dave MacQueen
P.S. You are running a fairly old version of the (legacy) SML/NJ compiler, version
110.79, while the current version is 110.99.4 (or 2023.1 for the "development" version), but I don't think this matters for this particular example.
On Feb 10, 2024, at 3:03 PM, Duke Normandin ***@***.***> wrote:
Noob is back! Reading "A Gentle Introduction to ML" by Andrew Cumming and doing the exercises.
The current exercise is asking to write a function such that when a string is input, the output is, e.g.
incFirst "bad" = "cad"
incFirst "shin" = "thin"
I came up with a solution that choked on my Linux box running
sml -h
Standard ML of New Jersey v110.79 [built: Tue Aug 8 16:57:33 2017]
So I cheated and looked at the solutions at the end of the book and found this:
fun incFirst s = chr(ord s + 1) ^ substring(s, 1, size s -1);
but it chokes the interpreter as well. Imagine!!
I sure could use some in-a-nutshell type of assistance please. TIA ..
—
Reply to this email directly, view it on GitHub <#282>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAGXNPPX336RDCUV5ZPE2VLYS74EDAVCNFSM6AAAAABDDBJXRWVHI2DSMVQWIX3LMV43ERDJONRXK43TNFXW4OZWGIYDIMZWHA>.
You are receiving this because you are subscribed to this thread.
David MacQueen
***@***.***
|
Beta Was this translation helpful? Give feedback.
-
|
On Sat, 10 Feb 2024 16:21:26 -0800 David MacQueen ***@***.***> wrote:
Thank you David!
[snip]
To summarize, you need to pay attention to the types of variables
(like “s”) and the operations that are applied to them, and make
sure that they are compatible. You also need to learn the “API”s
associated with characters and strings (in this case the Basis
structures (i.e., modules) Char and String) which provide ways to
transform values from one type to another (e.g. String.sub,
Char.ord, Char.chr, Char.toString) that here allow one to go from
strings to characters to ints and back again.
In this case, most of the functions you need (like “chr”, “ord”,
“sub”, “^”) happen to be available at “top level”, but not all
(e.g.. Char.toString). This means you need to become familiar
with the contents of Basis library structures like Char.
Yes indeed! I was doing just that when your email arrived.
Thanks for the coaching! I'm still confused as to why the solution
in the book failed - unless he was using a different flavour of SML?
--
Duke
|
Beta Was this translation helpful? Give feedback.
-
|
Actually this example, and its incorrect "book" solution, illustrate an interesting challenge for beginner SML programmers. My guess is that the book solution is wrong possibly because it is trying to stick to functions that have simple names in the default top level environment, while trying to avoid the complication that these functions actually are found as components of structures like Char and String. In this case, this attempt worked for the functions "ord", "chr", "substring" (which are synonyms for Since the set of functions bound to simple names in the top-level environment is somewhat arbitrary an idiosyncratic, this (i.e. programming only with functions named in the top-level environment) is not a realistic approach. One can't get around using structures like Char and String even in a seemingly simple programming task. This means that before solving even basic programming assignments using (e.g.) characters and strings, the modules ("structures") Char and String have to be explained and used, and their documentation (in this case via their signatures CHAR and STRING) has to be introduced. This means structures and their signatures can come into the picture at a very early point in learning SML. Even if one sticks to numbers, tuples, and lists, it might be necessary or useful to use functions from the List structure that are not bound at top level (e.g., List.concat), or one might encounter effects of overloading of numeric operations and literals (although defaulting of overloading resolution makes this less likely). |
Beta Was this translation helpful? Give feedback.
-
|
See the additional comment that I just added to this discussion. I have a feeling that the book author may have been trying
to have students do problems that required only functions that are defined (bound) in the top-level environment, but in this case
they didn’t take into account that the solution needed Char.toString, which is not named in the top-level environment (although a different function String.toString (!?) _is_ named “toString” in that environment.
In this textbook, were structures like Char and String discussed before this assignment? Or were functions like ord, chr, substring
discussed without mentioning “where they live” in the module system.
Dave
On Feb 10, 2024, at 4:58 PM, Duke Normandin ***@***.***> wrote:
On Sat, 10 Feb 2024 16:21:26 -0800
David MacQueen ***@***.***> wrote:
Thank you David!
[snip]
> To summarize, you need to pay attention to the types of variables
> (like “s”) and the operations that are applied to them, and make
> sure that they are compatible. You also need to learn the “API”s
> associated with characters and strings (in this case the Basis
> structures (i.e., modules) Char and String) which provide ways to
> transform values from one type to another (e.g. String.sub,
> Char.ord, Char.chr, Char.toString) that here allow one to go from
> strings to characters to ints and back again.
>
> In this case, most of the functions you need (like “chr”, “ord”,
> “sub”, “^”) happen to be available at “top level”, but not all
> (e.g.. Char.toString). This means you need to become familiar
> with the contents of Basis library structures like Char.
Yes indeed! I was doing just that when your email arrived.
Thanks for the coaching! I'm still confused as to why the solution
in the book failed - unless he was using a different flavour of SML?
--
Duke
—
Reply to this email directly, view it on GitHub <#282 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAGXNPLWER7D6JB32MSZX6DYTAJTJAVCNFSM6AAAAABDDBJXRWVHI2DSMVQWIX3LMV43SRDJONRXK43TNFXW4Q3PNVWWK3TUHM4DIMZQGQ3DK>.
You are receiving this because you commented.
David MacQueen
***@***.***
|
Beta Was this translation helpful? Give feedback.
-
|
On Sat, 10 Feb 2024 17:27:34 -0800 David MacQueen ***@***.***> wrote:
[snip]
In this textbook, were structures like Char and String discussed
before this assignment? Or were functions like ord, chr,
substring discussed without mentioning “where they live” in the
module system.
You nailed it! None of that was discussed. So maybe "gentle" or
not, I should look for another entry-level book on SML. Thx for the
explanation to that wrong solution - from Edinburgh Napier
University no less. Were they not heavily associated with ML early
on?
--
Duke
|
Beta Was this translation helpful? Give feedback.
-
|
How old is this book? That looks like a valid solution circa 1990 when there was no
character type, but with the 1997 Revision, the ord/chr functions work on characters
(not strings).
The following code will work:
fun incFirst s = str(chr(ord(String.sub(s, 0))+1)) ^ substring(s, 1, size s - 1);
… On Feb 10, 2024, at 17:03, Duke Normandin ***@***.***> wrote:
Noob is back! Reading "A Gentle Introduction to ML" by Andrew Cumming and doing the exercises.
The current exercise is asking to write a function such that when a string is input, the output is, e.g.
incFirst "bad" = "cad"
incFirst "shin" = "thin"
I came up with a solution that choked on my Linux box running
sml -h
Standard ML of New Jersey v110.79 [built: Tue Aug 8 16:57:33 2017]
So I cheated and looked at the solutions at the end of the book and found this:
fun incFirst s = chr(ord s + 1) ^ substring(s, 1, size s -1);
but it chokes the interpreter as well. Imagine!!
I sure could use some in-a-nutshell type of assistance please. TIA ..
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: ***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
|
On Sun, 11 Feb 2024 14:04:10 -0800 John Reppy ***@***.***> wrote:
How old is this book? That looks like a valid solution circa
1990 when there was no character type, but with the 1997
Revision, the ord/chr functions work on characters (not strings).
The following code will work:
fun incFirst s = str(chr(ord(String.sub(s, 0))+1)) ^
substring(s, 1, size s - 1);
Thanks John!
WOW! That's a "daisy-chain" of an expression! I'm slowly seeing
what functional programming looks like.
Lastly apologies to Andrew Cumming, the author of the book.
--
Duke
|
Beta Was this translation helpful? Give feedback.
-
|
That is interesting — I had forgotten the state of affairs before SML ’97 and the introduction of the Basis library.
I had also forgotten the str function defined at top level (where str = String.str). But again, what is in the set of top-level
function bindings is more or less accidental, though probably influenced by history. Many, but not all, of the functions in
String are in that set.
So this book is apparently old enough to predate the Basis library and its structures (as are several other early Standard
ML texts). A few texts such as Larry Paulson’s “ML for the Working Programmer” have second editions that were updated for
SML ’97 (defined in the book “The Definition of Standard ML, Revised”, MIT Press, 1997).
The author, Andrew Cummings, and the Heriot-Watt Computer Science department, were not involved in the design, development, and
implementation of Standard ML, as far as I can recall. The design mainly took place at Edinburgh University. There is an extensive “History of Standard ML” paper available on the History page of smlfamily.org <http://smlfamily.org/>, if you are interested in lots more detail about the history of the language.
On Feb 11, 2024, at 2:32 PM, Duke Normandin ***@***.***> wrote:
On Sun, 11 Feb 2024 14:04:10 -0800
John Reppy ***@***.***> wrote:
> How old is this book? That looks like a valid solution circa
> 1990 when there was no character type, but with the 1997
> Revision, the ord/chr functions work on characters (not strings).
>
> The following code will work:
>
> fun incFirst s = str(chr(ord(String.sub(s, 0))+1)) ^
> substring(s, 1, size s - 1);
Thanks John!
WOW! That's a "daisy-chain" of an expression! I'm slowly seeing
what functional programming looks like.
Lastly apologies to Andrew Cumming, the author of the book.
--
Duke
—
Reply to this email directly, view it on GitHub <#282 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAGXNPKN4W25QIGWPRU4NUDYTFBI5AVCNFSM6AAAAABDDBJXRWVHI2DSMVQWIX3LMV43SRDJONRXK43TNFXW4Q3PNVWWK3TUHM4DIMZWGAYTE>.
You are receiving this because you commented.
David MacQueen
***@***.***
|
Beta Was this translation helpful? Give feedback.
-
|
On Sun, 11 Feb 2024 20:14:18 -0800 David MacQueen ***@***.***> wrote:
There is an
extensive “History of Standard ML” paper available on the History
page of smlfamily.org <http://smlfamily.org/>, if you are
interested in lots more detail about the history of the language.
Thx!
--
Duke
|
Beta Was this translation helpful? Give feedback.
-
|
standardml.zulipchat.com <http://standardml.zulipchat.com/> is another forum where you can get answers and participate in discussions about SML the language and
SML/NJ the “system”.
Dave
On Feb 12, 2024, at 6:07 AM, Duke Normandin ***@***.***> wrote:
On Sun, 11 Feb 2024 20:14:18 -0800
David MacQueen ***@***.***> wrote:
> There is an
> extensive “History of Standard ML” paper available on the History
> page of smlfamily.org <http://smlfamily.org/>, if you are
> interested in lots more detail about the history of the language.
Thx!
--
Duke
—
Reply to this email directly, view it on GitHub <#282 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAGXNPORVVWJJGQPX673YL3YTIOYXAVCNFSM6AAAAABDDBJXRWVHI2DSMVQWIX3LMV43SRDJONRXK43TNFXW4Q3PNVWWK3TUHM4DINBSGE2TE>.
You are receiving this because you commented.
David MacQueen
***@***.***
|
Beta Was this translation helpful? Give feedback.
-
|
On Tue, 13 Feb 2024 13:32:32 -0800 David MacQueen ***@***.***> wrote:
standardml.zulipchat.com <http://standardml.zulipchat.com/> is
another forum where you can get answers and participate in
discussions about SML the language and SML/NJ the “system”.
Right! I'll check it out ...
--
Duke
|
Beta Was this translation helpful? Give feedback.
-
|
You may need an invitation link, which I can supply (given an email address).
Dave
On Feb 13, 2024, at 1:53 PM, Duke Normandin ***@***.***> wrote:
On Tue, 13 Feb 2024 13:32:32 -0800
David MacQueen ***@***.***> wrote:
> standardml.zulipchat.com <http://standardml.zulipchat.com/> is
> another forum where you can get answers and participate in
> discussions about SML the language and SML/NJ the “system”.
Right! I'll check it out ...
--
Duke
—
Reply to this email directly, view it on GitHub <#282 (comment)>, or unsubscribe <https://github.com/notifications/unsubscribe-auth/AAGXNPLBN4LG4NEYAGZKWC3YTPOGPAVCNFSM6AAAAABDDBJXRWVHI2DSMVQWIX3LMV43SRDJONRXK43TNFXW4Q3PNVWWK3TUHM4DINJZGA4DO>.
You are receiving this because you commented.
David MacQueen
***@***.***
|
Beta Was this translation helpful? Give feedback.
-
|
On Tue, 13 Feb 2024 16:10:54 -0800 David MacQueen ***@***.***> wrote:
You may need an invitation link, which I can supply (given an
email address).
Thanks for the offer David, but between Reddit and github, I think
that I'm okay for the moment.
--
Duke
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Noob is back! Reading "A Gentle Introduction to ML" by Andrew Cumming and doing the exercises.
The current exercise is asking to write a function such that when a string is input, the output is, e.g.
incFirst "bad" = "cad"
incFirst "shin" = "thin"
I came up with a solution that choked on my Linux box running
So I cheated and looked at the solutions at the end of the book and found this:
fun incFirst s = chr(ord s + 1) ^ substring(s, 1, size s -1);but it chokes the interpreter as well. Imagine!!
I sure could use some in-a-nutshell type of assistance please. TIA ..
Beta Was this translation helpful? Give feedback.
All reactions