`Cmd msg` 是什么意思?

What is the meaning of `Cmd msg`?

我正在尝试使用端口将 URL 传递给 Javascript,以便将用户重定向到另一个页面。我写了一个 port module 来包含我的项目所需的所有端口:

port module Utils exposing (..)
port changePage : String -> Cmd Event

然后,我将它导入到我的 Elm 文件中:

type Event = PageChange String
import Utils exposing (changePage)

但是编译器不喜欢它:

It looks like the keyword `import` is being used as a variable.
8| import Utils exposing (changePage)
         ^
Rename it to something else.

所以我将端口定义移到了主文件中:

type Event = PageChange String
port changePage : String -> Cmd Event

但是编译器还是不同意:

Port `changePage` has an invalid type.
28| port changePage : String -> Cmd Event
    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You are saying it should be:
 String -> Platform.Cmd.Cmd BmC.Index.Event
But you need to use the particular format described here:
<http://guide.elm-lang.org/interop/javascript.html#ports>

所以我去看了那个特定的格式,port check : String -> Cmd msg。我不明白那个msg是从哪里来的,所以我去查看code,我仍然不明白那一行是什么意思。

msg从何而来? type Cmd msg = Cmd 是什么意思?提前致谢。

Elm 中的端口声明在设计上需要非常具体的类型定义注释。

首先,我建议您研究 Reading Types,尤其是在提到 类型变量

的段落中

之后,请确保您熟悉 Generic Data Structures and if the official guide doesn't help, you can look into my answer to the similar question

端口有点混乱所以我打开了一个问题The guide on JavaScript interop should explain port function type definitions

传出端口

port out : String    ->    Cmd msg
              |                 |
              |                 |
          Concrete type    Generic type
          of outgoing      with `msg` type variable
          data             
                           Outgoing port never sends messages,
                           but you need to specify the type so the
                           compiler can infer, that you can use
                           this command to send the outgoing values
                           in any module, that imports "out" function

传入端口

port in : (List String -> msg)    ->    Sub msg
                     |                     |
                     |                     |
         A function, that accepts       Has to be generic,
         outgoing data and returns      because it is going to be
         a message. This function       a subscription with the
         is called "tagger"             same type as "tagger" returns

         Has to be generic, i.e. use
         `msg` type variable

import 语句必须出现在任何函数或类型定义之前。这就是您在此代码上遇到编译错误的原因:

type Event = PageChange String
import Utils exposing (changePage)

关于您的端口问题:Elm 的端口是架构边缘的一项功能。它们允许与不同的语言进行互操作,因此,出于所有意图和目的,幕后发生了一些魔法。

其他语言具有与其他语言互操作的类似 "magical" 结构。 Haskell 有 Foreign Function Interface (FFI) and C# has the extern 关键字来调用外部库。

Cmd 的定义是那些通过查看代码并没有真正意义的部分之一。

type Cmd msg = Cmd

这并不能告诉我们太多,但没关系。它更像是编译器在编译时填充的占位符。其他语言也这样做。 Haskell often uses a bottom call of let x = x in x 表示编译器将实际实现的功能。

所以,除非您真的对实现 Elm 和 Javascript 之间的交叉感兴趣,否则没关系,让它留给想象并接受魔法。

至于能够在您的端口中指定具体类型,那只是编译器团队的另一种选择。尽管 Cmd Event 是唯一可以通过端口的东西,他们还是选择强制使用通用类型作为 Cmd 的类型参数。不需要 Cmd msg 的准确拼写。 msg 可以是任何小写字母:

port check : String -> Cmd a

您的第一个编译器错误是因为您的 import 在定义之后,但要求的格式是让所有导入都在所有定义之前。

至于String -> Cmd msg中的msg是什么意思,它只是一个类型变量——Elm中类型注解中的所有小写类型名称都是类型变量,而以大写字母开头的是具体的类型。所以它与 String -> Cmd aString -> Cmd foo.

相同

在 Elm 中,就像在 Haskell 和其他一些函数式语言中一样,如果类型变量在类型注释中,则隐式为 universally quantified。所以我们把上面的类型读为

changePage : ∀msg.String → Cmd msg

即'for any type msg, changePage can take a String to a Cmd of msg'.

这意味着表达式 changePage "myPage.html" 可以在代码中任何需要某种类型命令的地方使用。这似乎有道理,因为它代表了'please send "myPage.html" to anyone subscribed to the changePage port'.

的命令