我有这样的信号:signal1 = Signal.constant {a=4, b=3, l = []}
如何从信号中提取数据?
我尝试了Signal.map (\x -> x) signal1
,但Signal.map
又返回了另一个信号。
答案 0 :(得分:4)
如果在Elm编程时遇到类似问题:
foldp
以及我应该传递哪些参数?” 你应该阅读The Elm Architecture教程并尝试在此过程中实现其代码。说真的,任何新手Elm程序员都应该从头到尾努力学习本教程,因为它会清除很多混乱。
尽管如此,我还是会给出一个简单的总结 - 请记住,我省略了许多细节和复杂性。如果您已经阅读了本教程,您可能会理解,典型的Elm程序是如何构建的。大多数Elm程序有3个主要部分:模型,更新和视图。
模型包含所有程序数据的初始值及其类型定义。 Update采用事件和模型,并根据事件返回修改后的模型。 View需要一个模型(在程序当前的任何阶段)并在屏幕上绘制它,换句话说,返回Element
。
在一个简单的程序中,只需将Signal.map
应用于渲染函数和信号,即可立即渲染信号发出的任何内容,而不存储任何中间状态。下面,函数show
扮演原始视图的角色。您不使用任何模型或更新,因为只要鼠标信号发出新事件,您就会立即渲染。
import Graphics.Element exposing (Element, show)
import Mouse
import Signal exposing (Signal, map)
main : Signal Element
main = map show Mouse.isDown
但是如果你想要maintain state between the events,你必须直接或通过一些更高级别的抽象来使用foldp
。按状态我的意思是你的模型,由更新功能的连续应用程序修改。在任何时间点,您的模型都处于某种状态。您的main
通常看起来像这样:
main = map view (foldp update model signal)
main
函数始终具有类型Signal Element
- 有异常,但在幕后它们仍会转换为Signal Element
。无论您对数据,代码和函数做什么,在某些时候您都必须将它们全部组合成Signal Element
类型的内容,这将是main
函数的主体。
模型通常是record,包含许多字段,其中任何字段也可以是记录。更新通常具有Event -> Model -> Model
类型,其中Model
是您的模型类型,Event
是您的最终信号发出的任何内容。视图通常具有类型Model -> Element
。 (类型名称不必是Event
和Model
,我在本例中将它们用作占位符。)
您无法从信号中提取值,这在Elm中是不可能的。相反,您使用Signal
将一个函数提升到Signal.map
上下文。信号发出的值的所有操作都是在Signal
上下文中通过提升到它的函数完成的。假设您的signal
类型为Signal Event
。然后foldp update model signal
将包含Signal Model
类型,因为foldp
的类型为:
foldp : (a -> state -> state) -> state -> Signal a -> Signal state
如果您的视图函数的类型为Model -> Element
,则map view (foldp update model signal)
将具有Signal Element
类型。
main
被授权使用Signal Element
类型,因此map view (foldp update model signal)
可以是main
的正文。
import Graphics.Element exposing (Element, show)
import Mouse
import Signal exposing (Signal, foldp, map)
type alias Model = Int
model : Model
model = 0
update : () -> Model -> Model
update event model = model + 1
view : Model -> Element
view model = show model
main : Signal Element
main = map view (foldp update model Mouse.clicks)
上面是一个非常简单的程序,可以累积鼠标点击次数。我们有一个虚拟事件,我们的模型只是一个整数。 Signal.map
函数如何工作?它的类型为:
map : (a -> b) -> Signal a -> Signal b
它需要一个普通函数将值转换为另一个值,并获取第一个值的信号,以产生第二个值的信号。假设您有许多不同的信号,它们会发出与鼠标点击,按键,定时事件,HTML输入字段,各种内容相对应的值。您可以按照自己喜欢的方式操作这些信号,但在某些时候,您将它们merge
转换为一个最终信号,类型为Signal Something
(其中Something对应于复杂的数据类型,包含程序所需的所有输入数据) )。
因为您必须拥有main
功能,所以在某些时候您必须将最终信号转换为Signal Element
,因此在某些时候您必须映射(提升)类型{{}}的函数{1}}超过Something -> Element
获取Signal Something
。为什么称为解除?由于partial application Signal Element
的这两种类型定义相同:
Signal.map
您将map : (a -> b) -> Signal a -> Signal b
map : (a -> b) -> (Signal a -> Signal b)
类型的普通日常功能提升到a -> b
上下文,以便它可以处理信号值而不仅仅是值。这是一个更复杂的例子,它计算秒和鼠标点击次数:
Signal
现在,我希望您能够基本了解Elm程序的结构以及如何处理信号发出的事件以及从事件到事件修改数据。现在,您可以通过添加更多信号来扩展上述程序,使您的模型更加复杂,并使您的视图更精彩地输出。
答案 1 :(得分:1)
这是故意几乎不可能的,因为你不应该这样做。
为什么呢?好吧,在Elm应用程序中查看main的一个可能签名可能会有所帮助:
main : Signal Element
在这里,我们声明我们的程序类型是一个元素信号;这意味着我们的程序是随时间变化的元素。 Elm运行时将为我们排序“随时间变化”位,只要我们让它知道我们关心的信号(通过引用它们),以及如何将它们连接在一起(使用map,foldp等)
如果您尝试访问内部值以将其显示为应用程序的一部分 - 正确的方法是使用该主要签名,让Elm执行信号解包。
如果您只想在运行时查看值(例如,在控制台日志中),请查看:
http://package.elm-lang.org/packages/elm-lang/core/2.1.0/Debug