当我们在Elm中使用类型变量定义类型别名时,会发生什么
假设我们将类型别名say当我们在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
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
,但是