函数式编程中的战斗机--elm编写实例(薛定鄂的猫)

  • 1.初始设置
  • 2.薛定谔的猫
  • 3.定义规则
  • 4.建立模型
  • 5.建立更新模型的逻辑
  • 6.构建前端界面
  • 7.连接代码
  • 8.运行程序

1.初始设置

今天编写一个elm应用实例。首先,做好初始设置。

Elm init

运行命令后,会在目录中创建一个elm.json配置文件,以及一个名为src的目录,我们在该目录中用编辑器。可以是vscode、atom等专门甚至最简单的记事本。在src目录中创建一个名为main.elm文件。该文件就是要编写应用代码的文件。

用编辑器打开文件,建议用vscode,最世界上最流行的程序代码编辑工具。

初次设置完成后,正式进入elm编程之旅。

2.薛定谔的猫

估计许多人都听说过薛定谔的猫的实验。在一个封闭的房间中放入一只活猫,房间中放置有毒药陷阱。因为房间是密封的。在房门关闭时,我们无法从外界观测到猫是死是活,因此猫处在一种非死非活的不确定性状态中;当我们打开房门时,可以观察到猫的状态,猫的死活也确定下来。薛定谔的猫阐述的是一种量子不确定现象。

我们的任务就是编写模拟薛定谔的猫实验的elm应用代码。

3.定义规则

我们需要定义一个包含门、锁、毒药陷阱(拔掉保险丝时开始运转)三种事物的房间。

规则1:如果门开,那么拔掉保险丝。

规则2:如果保险丝被拔掉,它能够重新放上。

规则3:如果门开,重新放保险丝。

规则4:如果门开,能关门。

规则5:如果门关,能开门或上锁。

规则6:如果上锁,能解锁。

每一种事物都可以用多种可能的状态组合表示,并且明确可能状态之间的转换规则是什么。

上述规矩转成对象状态如下:

– 可能的状态:

Door(门):Locked(上锁)Closed(关门)Opened(开门)Alarm(毒药陷阱):Armed (触发)Disarmed (没触发)Triggered(保险丝)--可能的状态组合有:Locked + Armed(上锁+毒药陷阱触发)Locked + Triggered(上锁+拔掉保险丝)Locked + Disarmed (上锁+毒药陷阱没有触发)Unlocked + Armed (开锁+毒药陷阱触发)Unlocked + Triggered (开锁+拔掉保险丝)Unlocked + Disarmed (开锁+毒药陷阱没有触发)Opened + Triggered (开门+拔掉保险丝)Opened + Disarmed(开门+毒药陷阱没有触发)--互相转换的状态有:Door(门):Closed <-> Locked (关门 <-> 上锁)Closed <-> Opened (关门 <-> 开门)Alarm(毒药陷阱):Armed -> Triggered (毒药陷阱触发 -> 拔掉保险丝)Triggered -> Disarmed (拔掉保险丝 -> 毒药陷阱没有触发)Armed <-> Disarmed (毒药陷阱触发 <-> 毒药陷阱没有触发)

4.建立模型

OK,规则确定好后,我们会发现,在监测开始的时间点,房间只能真正存在一种可能的状态组合。因此要定义一个显示房间状态的模型model,它包括了监测时间点时的状态等。这个模型要将失败的情景加上去,防止观测不到的错误产生,用自定义类型添加到mail.elm代码中去。

   type Model= DisplayingRoom DoorState AlarmState| Failure Stringtype DoorState= Opened| Closed| Lockedtype AlarmState= Armed| Disarmed| Triggered

好了,我们薛定谔的猫模型建立起来,完成第一步代码。

5.建立更新模型的逻辑

要对模型进行更新,必须要有信息通知到达才能开始更新。因此更新逻辑前需先定义消息:

   type Msg= Open| Close| Lock| Unlock| Arm| Disarm

消息定义后,开始定义update更新函数,实现消息->模型->返回一个新模型,我们先从检查房间状态开始定义:

   update msg model =case model ofDisplayingRoom doorState alarmState ->...Failure errorMessage ->model

先建立函数框架,如果因为故障原因无法观测到房间状态,那么更新函数只能返回原来的模型model。

当可以正常地观测房间时,如果房门处于打开状态下,受到的限制最大:门开、锁解、毒药陷阱不能起作用。

第一步,让我们添加房门打开时的更新代码,扩展原来基础框架:

   update : Msg -> Model -> Modelupdate msg model=case model ofDisplayingRoom doorState alarmState ->case doorState ofOpened ->case msg ofClose ->DisplayingRoom Closed alarmState_ -> Failure "故障,观测不到!”Failure _ ->model

直到门关,毒药陷阱才可能被触发。

上述代码中,我们处理了,房间由开门转为关门时模型的更新代码:

DisplayingRoom Closed alarmState

其中alarmState是包含了毒药陷阱触发或没有被触发两种状态的变量,确保门由开转关时。毒药陷阱的状态可以原封不动地转移到新的模型上。

 _ -> Failure "故障,观测不到!"

这是一个兜底代码,确保无法获取监测状态时返回一个消息通知。这种考虑周全的机制,也是elm编译运行不出错的优势。

第二步,让我们添加门关时的更新逻辑,较为复杂,打开门时,里面涉及到锁的状态、毒药陷阱的状态。

在门关的前提下,如果收到开门的消息,那么要检测毒药陷阱的状态,触发或没有触发。因为毒药陷阱的状态,关系到猫的死活。如果毒药陷阱一直不被触发,猫仍然存活。但这些在未打开房门的情况下,我们是无法监测而至的,现在添加门关情况下的代码。

   Closed ->casemsg ofOpen ->case alarmState ofArmed ->DisplayingRoom Opened Triggered_ ->DisplayingRoom Opened alarmStateLock ->DisplayingRoom Locked alarmStateArm ->DisplayingRoom Closed ArmedDisarm ->DisplayingRoom Closed Disarmed_ -> Failure "故障,观测不到!"

第三步,让我们添加门锁住情况下的更新代码:

   Locked ->case msg ofUnlock ->DisplayingRoom Closed alarmStateArm -> DisplayingRoom Locked ArmedDisarm -> DisplayingRoom Locked Disarmed_ -> Failure "故障,观测不到!"

好了,我们代码中最重要的引擎,update更新函数完成了。下一步是把更新后的模型通过UI视图显示出来,这对于elm来说轻而易举,因为它本身就是为了构建前端而生。

6.构建前端界面

elm有一个HTML库,它使我们可以在elm中编写HTML代码:

   import Html exposing (..)

现在通过来引入这个库,为简单起见,这里只是把房间的状态用文字在html界面中展示出来:

首先建立一个failure情况下的显示函数:

   failure message =div [][ p [] [ "故障,观测不到!" ] ]

然后把各种状态组合用文字展示出来,这里要注意的是,按照房间规则,门关时的状态要有两个可能的消息,但是门开时只需要一条消息即可。最后UI界面代码如下:

   View: Model -> Html Msgview model =Case model ofFailure message =div []p [] [ "故障,观测不到!" ] ]DispalyingRoom doorState alarmState=div [][case doorState ofOpened ->Div [][ p [] [ "门开-> 关门!" ] ]Closed =Div [][ p [] [ "门关-> 开门!" ] ]Locked =Div [][ p [] [ "门锁-> 开锁!" ] ]],div [][ case alarmState ofArmed ->Div [][ p [] [ "毒药陷阱被触发-> 开门!" ] ]disArmed ->Div [][ p [] [ "毒药陷阱没有触发-> 毒药陷阱被触发!" ] ]Triggered ->Div [][ p [] [ "拔掉保险丝-> 毒药陷阱被触发/毒药陷阱没有触发!" ] ]]

为简单起见,这里只用文字显示作为HTML的内容,但elm的HTML库还有许多强大的功能,可以与react的JSX比美。下回我们再尝试构建更绚丽的图象或动画显示房间状态。

7.连接代码

模型、更新、界面代码已经写好,剩下的是把这几部分连接起来。我们需要ELM的主核心Browser模块里面的沙箱sandbox:

   Import Browser exposing (..)

沙箱允许您创建使用elm架构的应用程序,但不会与”外部世界”对话(即任何外部的API或JavaScript,如果需要与外部世界对话可以用Browser.element或其它)。建立沙箱前我们还要声明一下房间的初始状态,假说为门已经关闭、猫已经放入、毒药陷阱的保险丝已经拔开。

   initialModel : ModelinitialModel = DisplayingRoom Closed Armedmain : Program () Model Msgmain = Browser.sandbox{ init = initialModel, view = view, update = update}

8.运行程序

在终端中运行命令:

  Elm make src/main.elm

Elm make 是elm的编译器命令,它把main.elm编译成一个html文件。可以用浏览器打个这个html文件,让我们作为观察者,通过开门、关门的点击操作来模拟这个薛定谔的猫的实验。

(备注:本周写的文章学习了尼莫的《我希望有的榆木示例》思路,三体状态不容易描述,用javascript写估计一大堆代码,elm容易读些,薛定谔的猫实验因为涉及到不确定性,应该还要引入随机发生器,有时间再慢慢改进。)

函数式编程中的战斗机--elm编写实例(薛定鄂的猫相关推荐

  1. 函数式编程中的战斗机(二) --运用elm语言MUV设计模式做一个简单的应用实例

    @函数式编程中的战斗机(二) -运用elm语言MUV设计模式做一个简单的应用实例 1 elm语言设计模式的特点 1.1 面向对象设计模式的特点 每种编程语言都有其独特的语法和优缺点,从而导致与众不同的 ...

  2. elm具体实现过程_函数式编程中的战斗机(二)---elm语言MUV设计模式应用实例...

    1 elm语言设计模式的特点 1.1 面向对象设计模式的特点 每种编程语言都有其独特的语法和优缺点,从而导致与众不同的设计模式和固定架构.面向对象编程因其竭力接近和模拟现实世界的多态和继承,导致面向对 ...

  3. 函数式编程中的组合子

    函数式编程是一个比较大的话题,里面的知识体系非常的丰富,在这里我并不想讲的特别的详细.为了应对实际中的应用,我们讲一下函数式编程中最为实用的应用方式--组合子.组合子本身是一种高阶函数,他的特点就是将 ...

  4. 函数式编程中的两个棘手问题

    作者 | Matthew Butt­erick 译者 | 弯月 出品 | CSDN(ID:CSDNnews) 大约从十年前,我开始使用Lisp编程语言,后来我喜欢上了函数式编程.每当使用非Lisp语言 ...

  5. 如何在函数式编程中存在时间函数?

    本文翻译自:How can a time function exist in functional programming? I've to admit that I don't know much ...

  6. 简单介绍函数式编程中的Functor(函子),Applicative(加强版函子),Monad(单子)

    原文地址:http://skaka.me/blog/2015/12/19/functor-applicative-monad-scala-haskell/ 如果你是刚接触函数式编程,可能很容易被下面这 ...

  7. less 函数_Python中的函数式编程教程,学会用一行代码搞定所有内容

    前言 在本文中,您将了解什么是函数范型,以及如何在Python中使用函数式编程.在Python中,函数式编程中的map和filter可以做与列表相同的事情.这打破了Python的禅宗规则之一,因此函数 ...

  8. Python函数式编程中map()、reduce()和filter()函数的用法

    Python中map().reduce()和filter()三个函数均是应用于序列的内置函数,分别对序列进行遍历.递归计算以及过滤操作.这三个内置函数在实际使用过程中常常和"行内函数&quo ...

  9. 多角度让你彻底明白yield语法糖的用法和原理及在C#函数式编程中的作用

    如果大家读过dapper源码,你会发现这内部有很多方法都用到了yield关键词,那yield到底是用来干嘛的,能不能拿掉,拿掉与不拿掉有多大的差别,首先上一段dapper中精简后的Query方法,先让 ...

最新文章

  1. 算法总结---最常用的五大算法(算法题思路)
  2. 适用于SQL Server生产环境DBA的七大技巧
  3. 火遍全国的网络热梗“yyds”,创造者被判刑3年
  4. 企业面试题库_数据库部分
  5. github使用-知乎的某小姐的一篇文章
  6. 怎么new一个指针_【译】Rust与智能指针
  7. VMware内存回收与分配机质
  8. Codeforces Round #703 (Div. 2) 题解
  9. 2021牛客暑期多校训练营3 B-Black and white(思维+最小生成树)
  10. 【learning】一种奇妙的网络流建模方式
  11. 【TWVRP】基于matlab禁忌搜索和节约算法求解带时间窗的车辆路径规划问题【含Matlab源码 1229期】
  12. android 新版本gradle,Android:更新到新版本的gradle后出现“Manife...
  13. VR、RTMP播放器SGPlayer原理详解
  14. ubuntu下搜狗拼音输入法不见了
  15. 关于QT 报错Error: Class declaration lacks Q_OBJECT macro.
  16. JavaWeb - 小米商城:商品详情展示
  17. 材料力学:使用matlab绘制铰支梁在多个集中力、集中力偶矩作用下的挠曲线
  18. Manjaro安装与软件硬件基本配置(保姆级)
  19. 字符串函数strtolower解析
  20. FPGA控制TDC-GPX2时间间隔测量(三)

热门文章

  1. 软件测试项目经验案例_自学软件测试如何得到项目经验
  2. 科讯CMS--将自己的ASP加进去
  3. 超简单易用,一款MySQL管理工具:Sequel Pro
  4. edHat linux光盘引导,RHEL6通过安装光盘或ISO文件制作本地yum源的方法
  5. photoshopCS3 不能即时刷新操作的解决方法
  6. 2020最新阿里云计算ACP考试笔记
  7. DISCUZ论坛插件h5手机电脑头像上传3.7.1带扩展插件【收集免费分享】
  8. 如何解决每次打开office2010都会出现正在配置
  9. 吴恩达机器学习(七)矩阵应用于数值预测
  10. koder code editor使用教程_教程 | 使用VS Code舒适地开发Verilog HDL V1.1