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
Sie sind frei SOME
im linken Teil des Ausdrucks verwenden:
val SOME x = Int.fromString "3";
val x = 3 : int
Sie die valOf
Funktion können Sie die einen gewissen Wert einer Option erhalten:
val i : int = valOf (Int.fromString "1")
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. –
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
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)
Danke @SimonShine. Die Idee ist cool. –
Vielen Dank! Es ist was ich brauchte. –