函数式编程简介匆忙:在浏览器中运行HaskellTDA555型/DIT440型2016年LP1
主页|地铁列车时刻表|实验室|讲座|练习|考试|关于|常见问题解答火灾|论坛|时间编辑|YouTube网站|链接
函数式编程简介匆忙:在浏览器中运行HaskellTDA555型/同上440,2016年第1版
主页|地铁列车时刻表|实验室|讲座|练习|考试|关于|常见问题解答火灾|论坛|时间编辑|YouTube网站|链接

链接:

介绍

匆忙是从Haskell到Java脚本,这是一种用于编程交互式网页的通用语言。通常,网页由HTML格式描述静态内容的文档,可能还有一些操纵页面并可能与用户交互的Javascript代码。在本课程中,我们将以这样一种方式使用Haster,它将为我们生成整个网页,包括Javascript。这样做的好处是,我们不必了解HTML或Javascript的任何内容。整个网页将在Haskell中描述。

继续之前,请确保已安装Haste:

注意:无论出于何种原因,如果您无法在自己的计算机上安装Haster,请不要花太多时间。最好将这些时间用于实验室作业,只需在Chalmers计算机上使用Haster即可。

本文档中开发的助手函数在模块中可用页码.hs(从本文档链接的其他Haskell文件也使用了该文件)。

你好,世界!

让我们从一个简单的“Hello world”示例开始:

进口匆忙主要的=警觉的“你好,世界!”

通过运行以下命令编译此程序

hastec—输出-html HelloWorld.hs

这将生成一个文件HelloWorld.html(HelloWorld)它在浏览器中加载时显示一个简单的文本框。

HelloWorld.hs(你好世界)

内容和布局

制作交互式网页的第一步是添加一些内容,这些内容以后可以作为用户交互的一部分进行操作。要做到这一点,人们必须了解这样一个事实,即网页在浏览器中表示为树结构对象,即所谓的文档对象模型(DOM)。

只包含一段文本的简单网页可以定义如下:

主要的= 文本<-新建文本元素“这是一些文字。”appendChild文档正文文本

do块中的第一行创建一个包含文本的所谓“元素”,第二行将此元素作为子元素添加到文档正文中(文档正文是文档树可见部分的根)。

在本课程中,我们不太关心创建文本网页——我们更感兴趣的是图形和交互式元素。首先,我们需要能够创建各种元素并根据某些布局放置它们。有不同的方法来创建布局,但我们将只使用一种非常简单的“逐栏”方法。

要按顺序向“父”元素添加多个“子”元素,我们只需使用appendChild(附加子项)按顺序多次:

主要的= 文本1<-新建文本元素“这是一些文字。”文本2<-新建文本元素“更多文本。”appendChild文档正文文本1追加子文档正文文本2

这将生成一个显示文本“This is some text.More text”的页面;也就是说,这两个文本已按顺序排列。为了向父级添加元素列表,我们使用以下帮助器函数:

appendChildren:: 元素 ->[元素]-> IO(输入输出)()appendChildren父子=sequence_[appendChild父级c|c(c)<-儿童]

如果子元素是“简单”元素(例如,如上所述的文本元素)appendChildren(附加子项)将它们水平放置,所以我们给出appendChildren(附加子项)一个替代名称,表示我们可以使用它在布局中构造行:

行:: 元素 ->[元素]-> IO(输入输出)()=appendChildren(附加子项)

(请注意元素类型表示DOM树中的节点。)

通过使用,我们的示例变得稍微简单:

主要的= 文本1<-新建文本元素“这是一些文字。”文本2<-新建文本电子表格“更多文本。”行文档正文[text1,text2]

我们的下一步是将元素放置在彼此之上,以实现垂直布局。这与创建行的方式几乎相同,只是我们首先需要将所有子元素包装在一个“div”元素中。包装如下:

wrapDiv:: 元素 -> IO(输入输出) 元素包装Div e= d日<-新元素“div”(div)appendChild d e返回d

将元素包装在“div”节点中的效果是,它将使用整个水平宽度,以便它旁边的元素将放置在它的上方或下方新元素可以用于创建任何名称的新元素,只有web浏览器可以理解的预定义元素集。“Div”就是其中之一。

现在的定义是:

列:: 元素 ->[元素]-> IO(输入输出)()列父级子级= 反恐精英<-序列[wrapDiv c|c(c)<-儿童]appendChildren父cs

演示如何使用为了创建布局,我们给出了以下示例,将四个元素放在两行中:

主要的= 文本1<-新建文本元素“左上角”文本2<-新建文本元素“右上角”文本3<-新建文本元素“左下角”文本4<-新建文本元素“右下角”topRow(顶行)<-新元素“div”  --最上面一行的容器底部行<-新元素“div”(div)  --最下面一行的容器行顶部行[text1,text2]行底部行[text3,text4]列文档正文[topRow,bottomRow]

简单文本.hs

需要有一个父元素来添加子元素,我们必须创建两个额外的元素topRow(顶行)底部行包含这两行。用于此目的的“Div”元素。

尽管上面的例子作为文本布局的一种方式看起来很愚蠢,但当我们考虑交互式和图形元素的布局时,它将变得非常有用。

交互式网页

要创建对用户输入作出反应的页面,可以使用按钮和文本条目(分别是“按钮”和“输入”元素)。下面是一个简单的示例,它使用下面的按钮创建文本条目:

主要的= 输入<-新元素“输入”按钮<-新元素“按钮”设置输入[道具“类型”  =: “文本”,道具“大小”  =: "30"  --箱子宽度,道具“价值” =: “在此处键入答案…”]设置按钮[道具“innerHTML” =: “提交答案”]列文档正文[input,button]

此示例将在浏览器中显示如下:

这个设置指令用于设置新元素的各种属性。我们不会在这里详细介绍这些财产;无论何时需要输入框或按钮,您都可以复制上述代码并更改相关字符串。

为了更容易地创建输入框和按钮,我们定义了两个辅助功能:

mk输入:: 国际 -> 字符串 -> IO(输入输出) 元素mk输入宽度初始化= 输入<-新元素“输入”设置输入[道具“类型”  =: “文本”,道具“大小”  =:显示宽度,道具“价值” =:初始化]返回输入mk按钮: 字符串 -> IO(输入输出) 元素mkButton标签= 按钮<-新元素“按钮”设置按钮[道具“innerHTML” =:标签]返回按钮

现在是时候让页面具有交互性了!假设我们想在单击按钮时更改框中的文本。以下是如何做到这一点:

主要的= 输入<-mk输入30 “在此处键入答案…”按钮<-mk按钮“提交答案”列文档正文[input,button]onEvent按钮单击 $\_-> 设置输入[道具]“价值” =: “你点击了!”]

同样,我们不会详细介绍它是如何工作的,但直观地说,最后一部分设置了一个“事件处理程序”,每当单击按钮时都会调用它。在这种情况下,事件处理程序只需更改输入元素,但处理程序可以任意复杂。

交互.hs

处理程序的参数(我们使用_)提供有关单击的信息(鼠标位置等)。这可能很有用,例如在游戏中捕捉鼠标点击,但在本例中我们没有使用它。

以下示例演示了如何在用户键入时读取输入框中的文本并将其复制到页面中的其他位置:

主要的= 输入<-mk输入30 ""输出<-新元素“span”列documentBody[输入,输出]onEvent输入松开键 $\_-> 文本<-getProp输入“价值”设置输出[道具]“innerHTML” =:文本]焦点输入

在这里,我们使用“span”元素来保存位于输入框下方的一段文本。事件处理程序由松开键每次释放键盘键时,即在输入框中键入每个字符后,都会运行。事件处理程序读取输入框的内容(“value”属性)并将其复制到输出元素。

命令焦点输入使输入框成为当前活动的元素,以便用户无需首先单击框即可开始键入。

回声.hs

计算器.hs 是一个类似的示例,但脚本实际计算结果,而不仅仅是复制文本。

浏览器中的图形

HTML5标准包括一个“canvas”元素,用于在浏览器中绘制图形。在我们的示例中,我们将使用以下函数来创建给定宽度和高度的画布:

mk画布:: 国际 -> 国际 -> IO(输入输出) 元素mkCanvas宽度高度= 帆布<-新元素“画布”setStyle画布“边框” “1px纯黑色”setStyle画布“背景颜色” “白色”设置画布[道具“宽度”  =:显示宽度,道具“高度” =:显示高度]返回画布

为了从Haskell代码与画布交互,首先必须导入Haster的画布库:

进口匆忙。绘图。帆布

此库包含两种用于创建图片的类型:形状图片。可以使用基本功能创建基本形状

行::  ->  -> 形状()矩形::  ->  -> 形状()圆::  -> 双精度 -> 形状()

A类是分别对应于x和y维中像素数的一对浮点数:

类型  =(双精度,双精度)

组合图片

形状是一种“指令类型”,就像例如。IO(输入输出),这意味着我们可以使用do符号来组合形状:

雪人:: 双精度 -> 形状()雪人x= 圆(x,100)20圆(x,65)15圆(x,40)10

一旦我们完成了形状,它可以变成图片以两种基本方式:

填充:: 形状()-> 图片()(打、击等的)一下:: 形状()-> 图片()

前者用纯色填充形状,而后者只绘制轮廓。图片也是“指令”类型,因此可以使用do-notation组合图片:

两个SnowMenInABox:: 图片()两个SnowMenInABox= 填满$雪人100$雪人200$矩形(50,10) (250,150)

这将产生以下图片:

绘制图片的主要功能如下:

主要:: IO(输入输出)()主要的= 帆布<-mk画布300 300appendChild文档正文画布只是可以<-获取画布渲染两个SnowMenInABox

雪人.hs

动画

只需定期重画图片,就可以在画布上制作动画。落球.hs 是一个落球的简单动画。这里,动画是通过函数实现的落下在20毫秒超时后递归调用自身。这个的论点落下充当状态动画;通过增加在递归调用中,每次迭代都会绘制出稍微不同的图片。

最后蹦蹦球.hs 是一个更高级的动画,通过使用鼠标在画布中单击以交互方式更新状态。为此IO参考用于保持当前状态。