问题
I want to write a function that takes a filename as a string and a list of pairs of characters. This function must open the named file, read the contents of the file, and echo the characters to the screen. Any occurrence of a character in the first position of a pair must be echoed as the character in the second position of the pair. For example, an invocation such as fileSubst "inputFile" [(#"a", #"b"), (#"b", #"z")] will echo the contents of inputFile with all occurrences of the character a replaced by the character b and all occurrences of the character b replaced by character z.
fun fileSubst (fileName : string, []) = nil
| fileSubst (fileName, (a,b)::cs) = let
val stream = TextIO.openIn fileName
TextIO.input1 = fileSubst (fileName,cs) in if isSome a
then print(Char.toString(a)) else TextIO.print end ;
回答1:
As @molbdnilo suggest, split this into several functions that might be useful in other contexts. You could divide this into one function that reads the file's content into a string,
fun readFile fname =
let val fd = TextIO.openIn fname
val contents = TextIO.inputAll fd
val _ = TextIO.closeIn fd
in contents end
a function that searches for the right mapping in a list of pairs of characters,
fun lookup [] needle = NONE
| lookup ((key,value)::haystack) needle =
if needle = key then SOME value else lookup haystack needle
a variation of this function that returns the key as a default value,
fun lookupDefault haystack needle =
Option.getOpt (lookup haystack needle, needle)
and a function that maps each character in a string to another one,
fun subst mapping = String.map (lookupDefault mapping)
You can then compose those to get one that operates on files. I'm not sure I would assume that a function call fileSubst "foo.txt" might read the file's content, perform the substitution and print the result to screen. Why wouldn't it write it back to file or return it as a string?
Since there are so many things you can do with a file's content, you could also make a more generic file handling function,
fun withFile fname f =
let val fd = TextIO.openIn fname
val contents = TextIO.inputAll fd
val _ = TextIO.closeIn fd
in f contents end
Then for example,
- withFile "helloworld.txt" (print o subst [(#"l", #"L")]);
HeLLo, WorLd!
By making generically useful functions you don't have to populate your library with highly specialized functions that are likely not going to be re-used much anyways.
来源:https://stackoverflow.com/questions/46538706/sml-function-that-takes-a-filename-and-a-list