当我们在Elm中使用类型变量定义类型别名时,会发生什么

当我们在Elm中使用类型变量定义类型别名时,会发生什么,elm,Elm,假设我们将类型别名sayMessage定义为: type alias Message a = { code : String , body : a } readMessage : Message () -> String readMessage message = ... 然后将函数readMessage定义为: type alias Message a = { code : String , body : a } readMessage : Message () -> Str

假设我们将类型别名say
Message
定义为:

type alias Message a =
{ code : String
, body : a
}
readMessage : Message () -> String
readMessage message =
...
然后将函数
readMessage
定义为:

type alias Message a =
{ code : String
, body : a
}
readMessage : Message () -> String
readMessage message =
...
上面的例子来自Elm教程,书中说:

此函数接收正文为空的消息。这是不一样的 与任何值一样,只有一个空值


有人能详细说明一下在上面的场景中到底发生了什么,以及编译器是如何处理它的。

除非你真的想看到它的内部编译器表示形式,我认为这里重要的是
任何值
空值
之间的区别

消息a
是一种带有1个参数的参数化类型。您可以将其作为模板阅读,例如,在
消息定义中出现小写
a
的地方,它将被具体类型(字符串、Int等)替换

因此,如果我们希望函数使用
字符串
正文接收
消息
,函数应该是这样的:

readMessage : Message String -> String
readMessage message =
此处发生的情况是,
body
字段的类型不再是
a
,而是
String
a
替换为
String
):

Elm中nothing(也称为
void
unit
)的值被编码为
()
。这就是为什么带有空正文值的
消息
如下所示:

{ code : String
, body : ()
}
readMessage : Message any -> String
readMessage message =
但是,当我们根本不关心body值时,我们可以使用
任意值获取
消息

readMessage : Message a -> String
readMessage message =
小写
a
可以是任何小写字符串,我们可以使其更可读,如下所示:

{ code : String
, body : ()
}
readMessage : Message any -> String
readMessage message =
但是我们不能真正阅读消息体,因为我们不知道它的类型(所以我们不知道如何阅读它)


希望这能有所帮助。

除非您真的想看到它的内部编译器表示形式,否则我认为这里重要的是
任何值
空值
之间的区别

消息a
是一种带有1个参数的参数化类型。您可以将其作为模板阅读,例如,在
消息定义中出现小写
a
的地方,它将被具体类型(字符串、Int等)替换

因此,如果我们希望函数使用
字符串
正文接收
消息
,函数应该是这样的:

readMessage : Message String -> String
readMessage message =
此处发生的情况是,
body
字段的类型不再是
a
,而是
String
a
替换为
String
):

Elm中nothing(也称为
void
unit
)的值被编码为
()
。这就是为什么带有空正文值的
消息
如下所示:

{ code : String
, body : ()
}
readMessage : Message any -> String
readMessage message =
但是,当我们根本不关心body值时,我们可以使用
任意值获取
消息

readMessage : Message a -> String
readMessage message =
小写
a
可以是任何小写字符串,我们可以使其更可读,如下所示:

{ code : String
, body : ()
}
readMessage : Message any -> String
readMessage message =
但是我们不能真正阅读消息体,因为我们不知道它的类型(所以我们不知道如何阅读它)

希望有帮助。

类型
消息()
是以下记录的别名:

{ code : String
, body : ()
}
其中,
()
类型表示没有任何项的元组(也称为空元组)。这种类型的值只有一个,并且它也被写入
()

现在,当我们想省略记录中的某个字段时,我们不能不指定它——这会让编译器发疯,另请参见。我们需要告诉编译器这个值可以省略

我们可以这样做的一种方法是使用类型,但如果我们制作了一个消息列表,允许我们在某些消息中包含正文,而在其他消息中省略正文。这可能不是我们想要的

另一种方法是像您在问题中所做的那样,参数化
消息
类型。这将允许我们在阅读邮件时使用
字符串
正文,在我们对正文不感兴趣时使用不同的正文类型

在这种情况下,我们需要考虑身体类型应该是什么。虽然我们可以使用空的
字符串
s来表示省略了正文的消息,但它们很容易与带有空正文的消息混淆。我们也可以使用
Bool
,但接下来我们需要决定是否要使用
True
False
作为省略的值。最后,我们可以使用空元组;因为它只有一个可能的价值,所以对我们来说是理想的

实际上还有一种可能性:我们可以创建一个
类型的别名MessageWithoutBody={code:String}
。在某些情况下(特别是当您需要省略更多字段时),这会更简洁,但由于您需要复制所有要保留的字段,因此可能会更详细。

类型
消息()
是以下记录的别名:

{ code : String
, body : ()
}
其中,
()
类型表示没有任何项的元组(也称为空元组)。这种类型的值只有一个,并且它也被写入
()

现在,当我们想省略记录中的某个字段时,我们不能不指定它——这会让编译器发疯,另请参见。我们需要告诉编译器这个值可以省略

我们可以这样做的一种方法是使用类型,但如果我们制作了一个消息列表,允许我们在某些消息中包含正文,而在其他消息中省略正文。这可能不是我们想要的

另一种方法是像您在问题中所做的那样,参数化
消息
类型。这将允许我们在阅读邮件时使用
字符串
正文,在我们对正文不感兴趣时使用不同的正文类型

在这种情况下,我们需要考虑身体类型应该是什么。虽然我们可以使用空的
字符串
s来表示省略了正文的消息,但它们很容易与带有空正文的消息混淆。我们也可以使用
Bool
,但是