异常具有极其有限的语义。必须精确地将它们扔到什么地方,或向上直接调用堆栈中进行处理,并且如果您忘记这样做,则在编译时没有向程序员的指示。
与Elm对比,其中Elm将错误编码为Results或Maybes,它们都是值。这意味着如果不处理该错误,则会出现编译器错误。您可以将它们存储在变量甚至集合中,以将它们的处理推迟到方便的时间。您可以创建一个函数来以特定于应用程序的方式处理错误,而不是到处重复非常相似的try-catch块。您可以将它们链接到一个仅在所有部分都成功的情况下才能成功的计算中,而不必将它们塞满一个try块。您不受内置语法的限制。
这与“吞下异常”完全不同。它使错误条件在类型系统中变得明确,并提供了更灵活的替代语义来处理它们。
考虑以下示例。如果您希望看到它的实际效果,可以将其粘贴到http://elm-lang.org/try中。
import Html exposing (Html, Attribute, beginnerProgram, text, div, input)
import Html.Attributes exposing (..)
import Html.Events exposing (onInput)
import String
main =
beginnerProgram { model = "", view = view, update = update }
-- UPDATE
type Msg = NewContent String
update (NewContent content) oldContent =
content
getDefault = Result.withDefault "Please enter an integer"
double = Result.map (\x -> x*2)
calculate = String.toInt >> double >> Result.map toString >> getDefault
-- VIEW
view content =
div []
[ input [ placeholder "Number to double", onInput NewContent, myStyle ] []
, div [ myStyle ] [ text (calculate content) ]
]
myStyle =
style
[ ("width", "100%")
, ("height", "40px")
, ("padding", "10px 0")
, ("font-size", "2em")
, ("text-align", "center")
]
请注意,String.toInt
在calculate
函数有失败的可能。在Java中,这有可能引发运行时异常。在读取用户输入时,它有很大的机会。Elm而是通过返回a来迫使我处理它Result
,但是请注意,我不必立即处理它。我可以将输入加倍并将其转换为字符串,然后检查getDefault
函数中是否有错误的输入。该位置比发生错误的位置或调用堆栈中向上的位置更适合进行检查。
与Java的检查异常相比,编译器强制我们执行操作的方式也要细得多。您需要使用非常具体的功能,例如Result.withDefault
提取所需的值。从技术上讲,您可能会滥用这种机制,但没有多大意义。由于您可以将决定推迟到知道正确的默认/错误消息后再进行,因此没有理由不使用它。