如何从自定义类型的多个变体中提取值?

HPa*_*ker 1 pattern-matching algebraic-data-types elm

我有一个像

type Post 
    = Blog String String
    | Announcement String String
Run Code Online (Sandbox Code Playgroud)

和类似的功能

upcaseTitle : Post -> Post
upcaseTitle post =
    case post of
        Blog title body ->
            { post | title = String.toUpper title }
        Announcement title body ->
            { post | title = String.toUpper title }
Run Code Online (Sandbox Code Playgroud)

我想写类似的代码,

upcaseTitle : Post -> Post
upcaseTitle post =
    case post of
        Post title body ->
            { post | title = String.toUpper title }
Run Code Online (Sandbox Code Playgroud)

我想在我添加一个条款case声明匹配所有Post类型和提取常见Stringtitle因为它是在我的工会类型的所有变体共享。

榆树有可能吗?

gle*_*nsl 6

不,不可能。在其他几种语言中,也可以使用or模式来实现(即使那样,您仍然必须枚举和解构每个变体,但是它们可以共享一个主体),但是Elm的目标是成为比这更简单的语言。

一种选择是将公共分支主体提取到函数中:

upcaseTitle : Post -> Post
upcaseTitle post =
    let
        setTitle title =
            { post | title = String.toUpper title }
    in
    case post of
        Blog title body ->
            setTitle title

        Announcement title body ->
            setTitle title
Run Code Online (Sandbox Code Playgroud)

另一个是定义一个单独的函数以仅提取标题:

getTitle : Post -> String
getTitle post =
    case post of
        Blog title body ->
            title

        Announcement title body ->
            title

upcaseTitle : Post -> Post
upcaseTitle post =
    { post | title = String.toUpper (getTitle post) }
Run Code Online (Sandbox Code Playgroud)

但是,如果您的自定义类型的每个变体都相同,那么我将首先质疑该类型的设计。也许最好使用帖子类型只是字段的记录呢?

type PostType
    = Blog
    | Announcement

type Post =
    { title : String
    , body : String
    , postType : PostType
    }
Run Code Online (Sandbox Code Playgroud)