CIS194 study notes: week 1 “Haskell Basics: Functions and Pictures”

这个系列会记录个人学习Haskell的过程,并假设读者至少了解一门OO语言和数据结构

课程地址:https://www.seas.upenn.edu/~cis194/fall16/index.html

online IDE(vital, 因为用到了提供的库):https://code.world/haskell

Haskell 是一种函数式编程语言,Functional, Pure, Lazy and Statically typed

第一段程序是画一个点出来

非常简单,主要是熟悉这门语言的运用

import CodeWorld
--引入CodeWorld库
ourPicture :: Picture
--这段含义是"ourPicture has type Picture"
ourPicture = solidCircle 1
main :: IO ()
--main 和C里的main相似,但注意类型是IO() 可能会导致违反 Pure
main = drawingOf ourPicture

要点1 :: 解释为 “has type” 声明类型使用,注意类型是固定的

要点2 ourPicture 声明为 solidCircle 1 之后不能再被声明,否则会报错"Multiple Declarations"重复声明 Haskell 中的=不是赋值,在其他常见的编程语言中重复赋值是可以接受的,因为赋值仅仅是把一个变量跟新值绑定而已。在Haskell中,=更接近 “定义”

接下来详细看下CodeWorld 提供的函数SolidCircle, 点击Online IDE 左下角的guide, search for solidCircle

solidCircle :: HasCallStack => Double -> Picture 
A solid circle, with this radius

注意=> 和 -> 的区别, => 的左边是约束类型,右边是实际类型, -> means "the arrow" 用来描述函数,在这个例子中解释为solidCircle函数输入为一个Double类型,输出一个Picture类型

注意Haskell的Functional特性,函数为第一公民,请注意以下区别

solidCircle (1+1)
solidCircle 1+1
第二行报错:No instance for (Num Picture) arising from a use of ‘+’

第二行会报错,因为函数是第一公民,编译器会先执行solidCircle 1,返回一个Picture。此时语句变成了Picture+1,注意不能把不同类型(看报错信息,Num Picture)相加,想要达到目的必须用小括号提高优先级

画一个黑点太单调了,接下来我们要把它变的好看一些

更改代码中ourPicture的声明,再次运行,点变成绿的了

ourPicture = colored green (solidCircle 1)

这里用到了一个新函数colored,查看IDE的guide, 查找colored,以下为描述

colored :: HasCallStack => Color -> Picture -> Picture
A picture drawn entirely in this color.

colored函数接受两个输入,类型分别是Color 和 Picture,返回一个Picture,所以上面那一行代码会先执行小括号中的solidCircle 1 返回一个Picture类型参数,这样就满足了colored的输入要求“Color -> Picture”,注意参数是用空格隔开的,而不是其他常见语言中的 ","

下面需要画两个点出来

将ourPicture声明更改,然后就看见两个不同颜色的点了

ourPicture = colored green (solidCircle 1) & solidCircle 2

查看guide中对&的描述,很明显接受两个Picture类型输入返回一个Picture,注意执行顺序为先执行小括号,然后执行所有函数,再执行&,所以只有一个点是绿的。

(&) :: Picture -> Picture -> Picture 
Binary composition of pictures.

接下来我们要移动这些点,并且画一个红绿灯出来

这里注意负值在Haskell中的写法,如果直接写x=-1是要报错的,因为"-"被看作一种操作符,所以必须写成x=(0-1)或者简写为x=(-1)

botCircleGreen = colored green (translated 0 (-1.5) (solidCircle 1))
topCircleRed   = colored red   (translated 0   1.5  (solidCircle 1))
frame = rectangle 2.5 5.5
trafficLight = botCircleGreen & topCircleRed & frame

ourPicture :: Picture
ourPicture = trafficLight

这里用到了一个新的函数translated, 查看guide,可知它接受三个参数,前两个Double为x,y方向上移动的距离,第三个为原来的Picture,最后返回一个新的Picture

translated :: HasCallStack => Double -> Double -> Picture -> Picture 

A picture drawn translated in these directions.

画出来之后如下图


接下来定义自己的函数

代码如下

botCircle c = colored c (translated 0 (-1.5) (solidCircle 1))
topCircle c = colored c (translated 0   1.5  (solidCircle 1))
frame = rectangle 2.5 5.5
trafficLight True  = botCircle green & topCircle black & frame
trafficLight False = botCircle black & topCircle red   & frame

ourPicture :: Picture
ourPicture = trafficLight True

这里定义了3个函数botCircle :: Color -> Picture, topCircle :: Color -> Picture 和 trafficLight :: Bool -> Picture,上面代码执行完之后会得到一个上面绿下面黑的红绿灯

接下来要让红绿灯动起来

做下面的更改

import CodeWorld
botCircle c = colored c (translated 0 (-1.5) (solidCircle 1))
topCircle c = colored c (translated 0   1.5  (solidCircle 1))
frame = rectangle 2.5 5.5
trafficLight True  = botCircle green & topCircle black & frame
trafficLight False = botCircle black & topCircle red   & frame
trafficController :: Double -> Picture
trafficController t
  | round (t/3) `mod` 2 == 0 = trafficLight True
  | otherwise                = trafficLight False

main :: IO ()
main = animationOf trafficController

注意main函数,更改为animationOf,查看guide发现该函数提供Double类型时间,接受第一个参数Picture,返回IO()。所以函数trafficController的输入Double其实是 animationOf 提供的,这部分需要仔细思考一下。

Haskell里和数字有关的类型和操作

Int: Int 最大值和操作系统的位数有关

Integer: Integer 只和机器的内存大小有关

Float和Double: 单双精度浮点数

操作:+ - * 对所有的数字类型都有效, /只对Double有效,对于整数请使用 div (除法) mod(取余),下面是一个直观的例子(in ghci)

Prelude> 6/2
3.0
Prelude> div 6 2
3

不能将不同类型的数据一起操作,比如浮点数加整数,注意Haskell不会自动转换类型,所以需要数据类型转换。假若需要将浮点型转为整形,需要round/floor/ceiling 即向上或向下取整。如果将整形转为其他数字类型则需要fromIntegral

注意不等于不是 != 而是 /=

递归

递归的意思是一个函数调用自己,并最终达到递归基。假设要画n个红绿灯,完整代码如下,注意lights函数,递归基是输入整形为0,则返回空,否则画出当前的Picture并&lights(n-1),由于translate位移的缘故这个函数可能看起来比较复杂。下面这段代码运行完之后应该画出三个红绿灯(或者说黑绿灯,hh). 注意这个online IDE可以被玩坏的,如果你调用一个负值的话代码会一直运行下去,hh

import CodeWorld
botCircle c = colored c (translated 0 (-1.5) (solidCircle 1))
topCircle c = colored c (translated 0   1.5  (solidCircle 1))
frame = rectangle 2.5 5.5
trafficLight True  = botCircle green & topCircle black & frame
trafficLight False = botCircle black & topCircle red   & frame
lights :: Integer -> Picture
lights 0 = blank
lights n = trafficLight True & translated 3 0 (lights (n-1))

ourPicture = lights 3

main = drawingOf ourPicture

代码注释

-- 这个和Java中的// 或者Python的#类似 单行注释
{-
多行注释
-}

第一周很简单,基本上就是了解语言的概念和基本语法/数据类型

编程作业: https://www.seas.upenn.edu/~cis194/fall16/hw/01-intro.html

ex1 红绿灯,没啥难的,四个阶段每个阶段持续时间不同(我用的是3s, 1s, 3s, 1s),对时间取余就行

botCircle, topCircle, midCircle :: Color -> Picture
botCircle c = colored c (translated 0 (-2.5) (solidCircle 1))
midCircle c = colored c (solidCircle 1)
topCircle c = colored c (translated 0   2.5  (solidCircle 1))

frame :: Picture
frame = rectangle 2.5 8.5

trafficLight :: Int -> Picture
trafficLight 0  = botCircle green & midCircle black & topCircle black & frame --green phase
trafficLight 1 = botCircle black & midCircle yellow & topCircle black   & frame --amber phase
trafficLight 2 = botCircle black & midCircle black & topCircle red   & frame --red phase
trafficLight 3 = botCircle black & midCircle yellow & topCircle red   & frame --red and amber phase

trafficController :: Double -> Picture
trafficController t
  | mod (round t) 8 >= 0 && mod (round t) 8<3 = trafficLight 0 --0,1,2
  | mod (round t) 8 == 3  = trafficLight 1 --3
  | mod (round t) 8 >= 4 && mod (round t) 8<7 = trafficLight 2 --4,5,6
  | mod (round t) 8 == 7  = trafficLight 3  --7

trafficLightAnimation :: Double -> Picture
trafficLightAnimation = trafficController

exercise1 :: IO ()
exercise1 = animationOf trafficLightAnimation

ex2 树上长花,和红绿灯一样

ex3 推箱子 自己定义外形,然后用translated来改变位置,最后画出UI


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
城市应急指挥系统是智慧城市建设的重要组成部分,旨在提高城市对突发事件的预防和处置能力。系统背景源于自然灾害和事故灾难频发,如汶川地震和日本大地震等,这些事件造成了巨大的人员伤亡和财产损失。随着城市化进程的加快,应急信息化建设面临信息资源分散、管理标准不统一等问题,需要通过统筹管理和技术创新来解决。 系统的设计思路是通过先进的技术手段,如物联网、射频识别、卫星定位等,构建一个具有强大信息感知和通信能力的网络和平台。这将促进不同部门和层次之间的信息共享、交流和整合,提高城市资源的利用效率,满足城市对各种信息的获取和使用需求。在“十二五”期间,应急信息化工作将依托这些技术,实现动态监控、风险管理、预警以及统一指挥调度。 应急指挥系统的建设目标是实现快速有效的应对各种突发事件,保障人民生命财产安全,减少社会危害和经济损失。系统将包括预测预警、模拟演练、辅助决策、态势分析等功能,以及应急值守、预案管理、GIS应用等基本应用。此外,还包括支撑平台的建设,如接警中心、视频会议、统一通信等基础设施。 系统的实施将涉及到应急网络建设、应急指挥、视频监控、卫星通信等多个方面。通过高度集成的系统,建立统一的信息接收和处理平台,实现多渠道接入和融合指挥调度。此外,还包括应急指挥中心基础平台建设、固定和移动应急指挥通信系统建设,以及应急队伍建设,确保能够迅速响应并有效处置各类突发事件。 项目的意义在于,它不仅是提升灾害监测预报水平和预警能力的重要科技支撑,也是实现预防和减轻重大灾害和事故损失的关键。通过实施城市应急指挥系统,可以加强社会管理和公共服务,构建和谐社会,为打造平安城市提供坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值