2016-04-10 11 views
2

Ich versuche, Integer-Wert aus einer Zeichenfolge mit Int.fromString Funktion zu extrahieren, aber wie wir wissen, ist die Spezifikation: String -> int option. Das Ergebnis der Anwendung Int.fromString ist also vom Typ int option. Aber ich brauche das Ergebnis vom Typ int. Ich bin mir auch sicher, dass der extrahierte Teil eine Ganzzahl ist. Wie kann das gemacht werden?Wie konvertiert String in int (und nicht in Int-Option) in SML

Antwort

2

Sie sind frei SOME im linken Teil des Ausdrucks verwenden:

val SOME x = Int.fromString "3"; 
val x = 3 : int 
+0

Vielen Dank! Es ist was ich brauchte. –

2

Sie die valOf Funktion können Sie die einen gewissen Wert einer Option erhalten:

val i : int = valOf (Int.fromString "1") 
+2

Dies ist sicherlich richtig und wichtig zu wissen (so +1), aber es ist überraschend, wie selten "valOf" tatsächlich benötigt wird. Guter Code sollte die Möglichkeit von "NONE" berücksichtigen, und der natürliche Weg dazu ist die Mustererkennung, aber Sie können auch ein Muster wie 'SOME x' verwenden, um den Wert zu extrahieren. –

+0

Ich habe festgestellt, eine Reihe von Fällen, wenn eine API selbst verbraucht und es gibt keinen anderen Fall, aber dies ist gültig. Dort habe ich es sowieso benutzt. – eatonphil

2

Wie @JohnColeman, Ich kann keine Teilfunktionen wie

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 empfehlen Sie müssen zumindest machen die Fehler sinnvoll, so dass Sie leicht aufspüren können, wenn Ihre invariant Pausen soll, weil es nur durch guten Willen im Namen des Programmierers bestätigt hat:

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

Die Funktion Int.fromString : string -> int option ist sicher, aber wenn Sie mag es nicht, könnten Sie tun:

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

val intFromString : string -> int -> int 

obwohl es ebenso selbstverständlich sein sollte NONE in der aufrufenden Funktion oder in einem spezialisierten Operator bind (>>=) zu handhaben. Dies geht auf das API-Design zurück, anstatt sichere Funktionen im Vergleich zu unsicheren Funktionen zu hinterfragen.

Wenn Sie sicher sind, dass eine Ganzzahl aus der Zeichenfolge extrahiert werden kann, warum diese Sicherheit nicht in einen Typ einbetten? Z.B. indem diese Zeichenketten in einen abstrakten Datentyp/Modul eingebettet werden, der nur die Erzeugung dieser sicherlich konvertierbaren Zeichenketten innerhalb des Moduls erlaubt. Eine minimale Implementierung könnte wie:

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 

An dieser Stelle ich die Verwendung von valOf rechtfertigen, weil ich die einzige Art und Weise kenne einen Wert vom Typ zu machen IntString.int_string durch IntString.fromInt ist. Das Modul könnte verwendet werden wie:

(* 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) 
+0

Danke @SimonShine. Die Idee ist cool. –