每周源代码34- F#的兴起


[原文发表地址]  The Weekly Source Code 34 - The Rise of F#

[原文发表时间]  2008-09-25 08:49 AM

首先,我要提醒大家,请大家看看我正在进行的最新的要求阅读源代码以编出更好的程序。亲爱的读者,我为大家呈上" 每周源代码."的第34篇,之后还将继续。

F#,大家都急于了解F#和它的功能,F#2008年九月的CTP是在几周前出来的。和我讨论的同事也正在努力发掘它。下面是我们的目标:

“为了研究编程语言而开发的F#将炙手可热的类型安全、简洁、性能、表达性脚本和高质量,获得良好支持的现代运行库系统相结合。”

它看起来更像一种研究语言,因为它内置于Visual Studio中,而且在语法突出显示、智能感知等方面都看起来很不错。亲爱的读者,这些信息对你来说可能是昨日黄花了,但是F#已经优化到更高的水平。这款发布将F#推向了和C# ,VB同等位置。它还有了自己的MSDN上的F# 研发中心。似乎还蛮有模有样的。

Vertigo's Rick Taylor在下面的图示中解释了F#的内容,意义以及方法:

“除非你特别制定,否则F#是不可改变的,在一定程度上有点像C#的构造字符串。它会拓展到一些你未曾预期的地方。例如,一旦你在一些特定值中设置了int,你就不能改变了,除非你将其标记为可以改变。出现这一情况的原因是语言是主要的功能之一。函数式语言的编程中包含函数的返回值-但是每个值或每个集合的值都是自己的实体,如果在一个方法中改变它,将产生副作用,即在功能语言中让人不快的因素严格意义上,函数返回值,但不会改变参数或外面的部分(这就附带的产生了前面提到的单子模式)。F#虽遵循函数编程的规则,但也允许使用可变关键字来打破这一规则。

学习F#的最佳途径是什么呢?这里倒有几个不错的办法。首先,有点高调的自我推销下吧,我和几个优秀的F#的开发人士合做了两个关于F#的博客,还做了几个不错的关于.NET Rocks和Herding Code episodes的博客。

* Starting Small with F# with Dustin Campbell

* F# with Robert Pickering

* .NET Rocks had Ted Neward and Amanda Laucher talking F# recently

* F# on Herding Code - Matt Podwysocki digging into F#

图书

  • 我很喜欢Robert的F#基础 这本书
  • 另外,如果你是个狂热的忍者火箭科学家,你也可以阅读" 为科学家开发的F#."。说真的,我个人非常建议你到Borders购买这本书。狂热的科学家。(说真的,这真书超级棒,你也可以看到一些免费的章节
  • Don Syme是开发F#的鼻祖,他的这本"F#专家"在市面上也有卖,而且销量极高。

F#博客

代码

C# 爱好者做的F# 介绍

然而,作为F#新秀,我有多年的Haskell经验,让我博得满堂彩的是LeonC# 爱好者做的F#介绍演示文稿的展示。我知道,这听起来令人难以置信。因为你可能了解到,Leon就是那个最近在澳大利亚TechEd的公众场合称我为Hanselgirl(我的名字其实是Hanselman的嚣张的家伙。我当即给了他一记耳光。我们还公开比腕力。我们两个之间肯定有互相合作的潜力,但是我跑题了。你可以点击在这里下载下载他的deck ,我也很不客气地把它传到了SlideShare上,并C# 爱好者做的F# 介绍

查看SlideShare网站的显示上传

(标签: f# c#)

我把第45至45张幻灯片智能化了,但是他描述的方法是点击。他做的也正是我想做的:

“我是靠Reflecto完成的,不是靠看书,论文或听播客或拷问高手。一个简单的let语句实质上就是一个静态函数。当你看到let,你就应该想到函数。

看看那些幻灯片吧。这是个不错的平台,我保证Leon不会介意的。亲爱的读者,在你的本地用户组显示他的谈话吧,或者在工作之余享受一次程序员午餐,并把功劳归功于它。这也是我为什么计划这么周全的原因。Suck it Bambrick!*

让我们看看三个代码位置。

首先,基本的。

记住,没有变量,也无副作用。

 1: #light

 2: 

 3: let sqr x = x * x 

 4: let multiply x y = x * y

 5: 

 6: print_int (sqr 3) 

 7: print_int (multiply 3 4)

 8: 

 9: // recursive function fibonacci series using pattern matching 

 10: let rec fib x = 

 11: match x with 

 12: | x when x <= 0 -> failwith "An integer greater than 0 is required." 

 13: | 1 -> 1 

 14: | 2 -> 1 

 15: | x -> fib (x - 1) + fib (x - 2) 

 16:  

 17: print_int (fib 15)

 18: 

 19: // functions as values 

 20: let add x y = x + y 

 21: let a1 = add 3 

 22: let a2 = a1 4 

 23: 

 24: print_int a2

其次,较出彩的。

F#中的度量单位。什么?太巧了吧,Andrew Kennedy13年前的博士论文写的就是关于F#的性能。他的论文分为三个部分:

基本上他们为度量单位添加了静态检查和推论。并没有介绍具体的东西,只是介绍了度量单位概念本身。

“就F#而论,ftm之间是没有任何关系的。由程序员自主定义合适的换算系数。”

这张图从他博客上截下来的,有近千个单词,展示了FSharp,Math,PhysicalConstants namespace和国际单位制(SI)命名空间。

image

同样,下面是从Andrew博客上截下来的:

你可以用”and”互相定义递归测度把它们连接起来,并把度量属性置于度量名称之前。“

 1: type [<Measure>] km = 

 2: static member toM = 1.0/1000.0<m/km> 

 3: and [<Measure>] m = 

 4: static member toKm = 1000.0<km/m>

第三,较愚蠢的

Phil Trelford从去年开始,仅仅用182行F#编写了有趣的2D Tron-Clone游戏。你可以hubFS下载它,参见他怎样在Applied Games Group Blog上写出它。该游戏还支持Xbox 360 controllers哦!真是太棒了。

image

下面是所有的182行代码,前四行的评论不包括在内。

 1: //-----------------------------------------------------------------------------

 2: // LightCycles.fs Mini game using windows forms

 3: // 2007 written by Phillip Trelford

 4: //-----------------------------------------------------------------------------

 5:  

 6: #light

 7:  

 8: #if DIRECTX

 9: #R @"C:\WINDOWS\assembly\GAC_32\Microsoft.DirectX\2.0.0.0__31bf3856ad364e35\Microsoft.DirectX.dll" // Feb 206

 10: open Microsoft.DirectX.XInput // Required to read XBox 360 controllers

 11: #endif

 12:  

 13: open System

 14: open System.Drawing

 15: open System.Windows.Forms

 16:  

 17: /// Game states

 18: type GameState = | Start | Play | Over

 19:  

 20: /// Form key handler type

 21: type KeyHandler (form:Form) =

 22: do form.KeyPreview <- true 

 23: let keys = Enum.GetValues (type Keys) :?> (Keys [])

 24: let keysDown = Array.create keys.Length false

 25: let FindKeyIndex code = keys |> Array.find_index (fun x -> code = x)

 26: do form.KeyDown.Add (fun e -> keysDown.[FindKeyIndex e.KeyCode] <- true)

 27: do form.KeyUp.Add (fun e -> keysDown.[FindKeyIndex e.KeyCode] <- false) 

 28: member this.IsKeyDown (keyCode:Keys) = keysDown.[FindKeyIndex keyCode] 

 29: member this.AnyKeyDown () = keysDown |> Array.exists (fun x -> x) 

 30:  

 31: /// Player direction type

 32: type Direction = | Left | Right | Up | Down

 33: 

 34: /// Player type

 35: type Player (color,startX,startY,direction,keys,keyHandler:KeyHandler) =

 36: let mutable x = startX

 37: let mutable y = startY

 38: let mutable d = direction

 39: 

 40: member this.Color = color

 41: member this.X = x

 42: member this.Y = y

 43: member this.Keys = keys

 44: 

 45: /// Reset player to start values

 46: member this.Reset () = x <- startX; y <- startY; d <- direction 

 47: 

 48: /// Updates player position 

 49: member this.Update i =

 50: // Read keyborad

 51: let mutable newD = d

 52: let up, down, left, right = keys

 53: if keyHandler.IsKeyDown(up) then newD <- Up

 54: if keyHandler.IsKeyDown(down) then newD <- Down

 55: if keyHandler.IsKeyDown(left) then newD <- Left

 56: if keyHandler.IsKeyDown(right) then newD <- Right

 57: #if DIRECTX 

 58: // Read XBox 360 controller 

 59: let state = Controller.GetState(i)

 60: if state.IsConnected then

 61: let pad = state.GamePad

 62: if pad.UpButton then newD <- Up

 63: if pad.DownButton then newD <- Down

 64: if pad.LeftButton then newD <- Left

 65: if pad.RightButton then newD <- Right

 66: #endif 

 67: /// Don't allow suicide move

 68: match (d,newD) with

 69: | (Left, Right) | (Right, Left) | (Up, Down) | (Down, Up) -> ()

 70: | _ -> d <- newD 

 71: /// Update position with direction 

 72: match d with

 73: | Up -> y <- y - 1

 74: | Down -> y <- y + 1

 75: | Left -> x <- x - 1

 76: | Right -> x <- x + 1

 77: 

 78: /// Main form 

 79: let form = new Form (Text="Light Cycles", Width=680, Height=544) 

 80:  

 81: do /// Layout for game window and status panel

 82: let layout = new TableLayoutPanel(Dock=DockStyle.Fill, ColumnCount = 2) 

 83: layout.ColumnStyles.Add( ColumnStyle(SizeType = SizeType.Percent, Width = 100.0f ) ) |> ignore

 84: layout.ColumnStyles.Add( ColumnStyle(SizeType = SizeType.Absolute, Width = 128.0f) ) |> ignore

 85: /// Play area in pixels

 86: let playArea = 500

 87: /// Game play area bitmap

 88: let bm = new Bitmap(playArea, playArea)

 89: /// Clears screen

 90: let ClearScreen () = 

 91: using (Graphics.FromImage(bm)) (fun graphics -> graphics.Clear(Color.Black))

 92: /// Draws text to screen

 93: let DrawText s =

 94: using (Graphics.FromImage(bm)) (fun graphics -> 

 95: let rect = new RectangleF(0.0f,0.0f,float32 playArea,float32 playArea)

 96: let align = new StringFormat(Alignment=StringAlignment.Center, LineAlignment=StringAlignment.Center)

 97: graphics.DrawString(s, form.Font, Brushes.White, rect, align)

 98: ) 

 99: // Initialise screen 

 100: ClearScreen ()

 101: DrawText "Press any key to start" 

 102: /// PictureBox to contain game bitmap

 103: let pictureBox = new PictureBox(Dock=DockStyle.Fill)

 104: pictureBox.Image <- bm 

 105: layout.Controls.Add(pictureBox) 

 106: 

 107: let keyHandler = KeyHandler (form)

 108: 

 109: /// Players array 

 110: let players = 

 111: [| Player (Color.Red,playArea/2+20,playArea/2,Down,(Keys.Q,Keys.A,Keys.Z,Keys.X),keyHandler); 

 112: Player (Color.LightBlue,playArea/2-20,playArea/2,Up,(Keys.P,Keys.L,Keys.N,Keys.M),keyHandler) |]

 113: players |> Array.iter (fun player -> bm.SetPixel(player.X,player.Y,player.Color)) 

 114: 

 115: /// Display player controls

 116: let statusPanel = new TableLayoutPanel(Dock=DockStyle.Fill, ColumnCount=1, BackColor=Color.DarkGray)

 117: players |> Array.iteri (fun i player ->

 118: let name = 

 119: [| ((new Label (Text=sprintf "Player %d" i, ForeColor=player.Color)) :> Control) |]

 120: let up, down, left, right = player.Keys

 121: let controls = 

 122: Array.combine [|"Up";"Down";"Left";"Right"|] [|up;down;left;right|]

 123: |> Array.map (fun (name,key) -> (new Label (Text=sprintf "%s '%O'" name key)) :> Control )

 124: Array.append name controls

 125: |> statusPanel.Controls.AddRange

 126: )

 127: layout.Controls.Add(statusPanel)

 128: form.Controls.Add(layout) 

 129:  

 130: /// Game play - returns true if there has been a collision otherwise false

 131: let PlayGame () = 

 132: let collisions = players |> Array.mapi (fun i player -> 

 133: player.Update i

 134: let x, y = (player.X, player.Y)

 135: let wall = x < 0 || x >= playArea || y < 0 || y >= playArea

 136: if wall then

 137: true

 138: else 

 139: let bgColor = bm.GetPixel(x, y) 

 140: bm.SetPixel (x, y, player.Color)

 141: players |> Array.exists (fun player -> let c = player.Color in c.R = bgColor.R && c.G = bgColor.G && c.B = bgColor.B ) 

 142: ) 

 143: pictureBox.Refresh ()

 144: 

 145: match collisions |> Array.tryfind_index (fun x -> x = true) with

 146: | Some(i) -> i

 147: | None -> (-1) 

 148: 

 149: /// Current game state

 150: let gameState = ref GameState.Start

 151: let gameOverWaitCount = ref 200

 152: let r = new Random()

 153: 

 154: /// Timer instance

 155: let timer = new Timer()

 156: timer.Interval <- 1000/50

 157: // Timer event

 158: timer.Tick.Add (fun _ ->

 159: match !gameState with

 160: | Start ->

 161: if keyHandler.AnyKeyDown () then 

 162: ClearScreen () 

 163: gameState := GameState.Play

 164: 

 165: | Play -> 

 166: let i = PlayGame ()

 167: if i>=0 then 

 168: gameState := GameState.Over

 169: gameOverWaitCount := 200

 170: DrawText (sprintf "Game Over - Play %d Lost" i)

 171: pictureBox.Refresh () 

 172: | Over -> 

 173: // Shake screen

 174: form.Left <- form.Left + if !gameOverWaitCount > 150 then r.Next(5) - 2 else 0

 175: // Decrement Game Over wait

 176: decr gameOverWaitCount

 177: if !gameOverWaitCount <= 0 then 

 178: gameState := GameState.Start

 179: players |> Array.iter (fun player -> player.Reset ())

 180: ClearScreen ()

 181: DrawText "Press any key to start"

 182: pictureBox.Refresh () 

 183: ) 

 184: timer.Start ()

 185: 

 186: [<STAThread>] 

 187: do Application.Run(form)


尝试每一年都学习一样新的语言

Comments (0)

Skip to main content