`Cmd msg`是什么意思?

时间:2016-12-23 19:42:59

标签: elm elm-architecture

我正在尝试使用端口将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是什么意思?提前谢谢。

3 个答案:

答案 0 :(得分:9)

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

type Event = PageChange String
import Utils exposing (changePage)

关于端口的问题:Elm的端口是一个位于架构边缘的功能。它们允许使用不同的语言进行互操作,因此,无论出于何种目的,在幕后都会有一些魔力。

其他语言具有与其他语言互操作的类似“神奇”结构。 Haskell有Foreign Function Interface (FFI),C#有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

答案 1 :(得分:4)

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

我建议首先考虑Reading Types,尤其是提及类型变量的段落

在此之后,请确保您熟悉Generic Data Structures,如果官方指南没有帮助,您可以查看我对类似问题的回答Understanding generic union types in Elm

端口有点令人困惑所以我打开了一个问题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

答案 2 :(得分:1)

您的第一个编译错误是因为您的import成功定义,但所需的格式是所有导入都在所有定义之前。

至于msgString -> Cmd msg的含义,它只是一个类型变量 - Elm中类型注释中的所有小写类型名称都是类型变量,而以大写字母开头的那些是具体类型。因此它与String -> Cmd aString -> Cmd foo相同。

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

changePage : ∀msg.String → Cmd msg

即,对于任何类型msgchangePage可以String Cmd msg&#39;。

这意味着表达式changePage "myPage.html"可以在您想要某种类型命令的代码中的任何位置使用。这似乎是有道理的,因为它代表了“"myPage.html"发送给changePage端口&#39;”的任何人的命令。