5

I am trying to extract integer value from a string using Int.fromString function but as we know, its specification is : String -> int option. So the result of applying Int.fromString is of type int option. But I need the result of type int. Also I am sure that the extracted part is integer. How can this be done?

Ankit Shubham
  • 2,989
  • 2
  • 36
  • 61

3 Answers3

4

You are free to use SOME in the left part of expression:

val SOME x = Int.fromString "3";
val x = 3 : int
barti_ddu
  • 10,179
  • 1
  • 45
  • 53
4

You can use the valOf function to get the SOME value of an option:

val i : int = valOf (Int.fromString "1")
eatonphil
  • 13,115
  • 27
  • 76
  • 133
  • 2
    This is certainly true and is important to know (so +1), but it is surprising how rarely `valOf` is actually needed. Good code should take the possibility of `NONE` into account, and the natural way to do so is with pattern matching, but then you might as well use a pattern like `SOME x` to extract the value. – John Coleman Apr 10 '16 at 22:24
  • I have noticed a number of cases when an API consumes itself and there is no other case but for this to be valid. That is where I've used it anyway. – eatonphil Apr 11 '16 at 10:24
3

Like @JohnColeman, I cannot recommend partial functions like

fun intFromString s = let val SOME i = Int.fromString s in i end

fun intFromString s = case Int.fromString s of SOME i => i

fun intFromString s = valOf (Int.fromString s)

If you must, at least make the error meaningful so you can easily track it down when your supposed invariant breaks because it's only upheld by good will on behalf of the programmer:

fun intFromString s =
    case Int.fromString s of
         SOME i => i
       | NONE => raise Fail ("Could not convert string '" ^ s ^ "' to int!")

The function Int.fromString : string -> int option is safe, but if you don't like it, you could do:

fun intFromString s default_i =
    Option.getOpt (Int.fromString s, default_i)

val intFromString : string -> int -> int

although it should be just as natural to handle NONE in the calling function, or in a specialized bind operator (>>=). This comes down to API design, rather than questions safe functions vs. unsafe functions.

If you are certain that an integer can be extracted from the string, why not embed this certainty in a type? E.g. by wrapping these strings in an abstract datatype / module that only allows the production of these certainly convertible strings from within the module. A minimal implementation could be like:

signature INT_STRING =
sig
    type int_string
    val fromInt : int -> int_string
    val toInt : int_string -> int
    val lift : (string -> 'a) -> (int_string -> 'a)
end

structure IntString :> INT_STRING =
struct
    type int_string = string
    fun fromInt i =
        if (i < 0)
        then "-" ^ Int.toString (Int.abs i)
        else Int.toString i

    fun toInt s =
        if String.sub (s, 0) = #"-"
        then ~ (valOf (Int.fromString (String.extract (s, 1, NONE))))
        else valOf (Int.fromString s)

    fun lift f s = f s
end

At this point I justify the use of valOf because I know the only way to make a value of type IntString.int_string is through IntString.fromInt. The module could be used like:

(* This property can be tested for arbitrary inputs i. *)
val id_prop i = IntString.toInt (IntString.fromInt i) = i
val test1 = id_prop 123
val test2 = id_prop ~55
val test3 = id_prop 0

(* Some standard string functions work just as well. *)
val intStringSize = IntString.lift String.size
val intStringPrint = IntString.lift String.print

val test4 = intStringSize (IntString.fromInt 555) = 3
val _ = intStringPrint (IntString.fromInt 12345)
sshine
  • 15,635
  • 1
  • 41
  • 66