通过游戏开发学习F#第3章错误

通过游戏开发学习F#第3章错误,f#,F#,我正在阅读《通过游戏开发学习》一书,在第3章中,我得到了一个TypeInitializationException,代码如下: // edit: missing definitions, thanks John let earth_mass = 5.97e24<kg> // defined in other file that is ref'd in ok let moon_mass = 7.35e22<kg> let lerp (x:float<'T>)

我正在阅读《通过游戏开发学习》一书,在第3章中,我得到了一个TypeInitializationException,代码如下:

// edit: missing definitions, thanks John
let earth_mass  = 5.97e24<kg> // defined in other file that is ref'd in ok
let moon_mass = 7.35e22<kg>

let lerp (x:float<'T>) (y:float<'T>) (a:float) = (x * a) + (y * (1.0 - a))
// inside list comprehension for loop -
let m = (lerp earth_mass moon_mass (rand.NextDouble())) * 1.0e-4 // error!!
//编辑:缺少定义,谢谢John
让earth_mass=5.97e24//在ok中引用的其他文件中定义
让月球的质量=7.35e22
设lerp(x:float)(a:float)=(x*a)+(y*(1.0-a))
//循环的内部列表理解-
设m=(lerp地球质量月球质量(rand.NextDouble())*1.0e-4//错误!!
我已经下载了作者的源代码,看看我是否遗漏了什么,但它会产生同样的错误。 异常消息对问题是什么(至少对我来说)没有什么线索

以下是本章的全部代码,以供参考:

namespace Games

module Chapter3 =
open System
open System.Threading
open Games.Math

type Asteroid =
    {
    Position : Vector2<m>
    Velocity : Vector2<m/s>
    Mass     : float<kg>
    Name     : string
    }

let dt = 60.0<s>
let G = 6.67e-11<m^3 * kg^-1 * s^-2>

let earth_radius = 6.37e6<m>
let field_size = earth_radius * 60.0
let max_velocity = 2.3e4<m/s>
let earth_mass  = 5.97e24<kg>
let moon_mass = 7.35e22<kg>

let create_field num_asteroids =
    let lerp (x:float<'T>) (y:float<'T>) (a:float) = x * a + y * (1.0 - a)
    let rand = Random()
    [
    for i = 1 to num_asteroids do
        let m = (lerp earth_mass moon_mass (rand.NextDouble())) * 1.0e-4
        let x = lerp 0.0<m> field_size (rand.NextDouble())
        let y = lerp 0.0<m> field_size (rand.NextDouble())
        let vx = max_velocity * (rand.NextDouble() * 2.0 - 1.0) * 0.1
        let vy = max_velocity * (rand.NextDouble() * 2.0 - 1.0) * 0.1

        yield
            {
            Position = { X = x; Y = y}
            Velocity = { X = vx; Y = vy}
            Mass = m
            Name = "a"
            }
    ]

let f0 = create_field 20

let clamp (p:Vector2<_>, v:Vector2<_>) = 
    let p,v =
        if p.X < 0.0<_> then
            {p with X = 0.0<_>}, {v with X = -v.X}
        else
            p,v
    let p,v =
        if p.X > field_size then
            {p with X = field_size}, {v with X = -v.X}
        else
            p,v
    let p,v =
        if p.Y < 0.0<_> then
            {p with Y = 0.0<_>}, {v with Y = -v.Y}
        else
            p,v
    let p,v =
        if p.Y > field_size then
            {p with Y = field_size}, {v with Y = -v.Y}
        else
            p,v
    p,v

let force (a:Asteroid, a':Asteroid) =
    let dir = a'.Position - a.Position
    let dist = dir.Length + 1.0<m>
    G * a.Mass * a'.Mass * dir/(dist * dist * dist)

let simulation_step (asteroids:Asteroid list) =
    [
        for a in asteroids do
            let forces =
                [
                    for a' in asteroids do
                        if a' <> a then
                            yield force(a, a')
                ]    
            let F = List.sum forces
            let p', v' = clamp(a.Position, a.Velocity)
            yield
                {
                    a with
                        Position = p' + dt * v'
                        Velocity = v' + dt * F/a.Mass
                }
    ]

let print_scene (asteroids:Asteroid list) =
    do Console.Clear()
    for i = 0 to 79 do
        Console.SetCursorPosition(i, 0)
        Console.Write("*")
        Console.SetCursorPosition(i, 23)
        Console.Write("*")
    for j = 0 to 23 do
        Console.SetCursorPosition(0, j)
        Console.Write("*")
        Console.SetCursorPosition(79, j)
        Console.Write("*")
    let set_cursor_on_body b =
        Console.SetCursorPosition(
            ((b.Position.X/4.0e8<m>) * 78.0 + 1.0) |> int,
            ((b.Position.Y/4.0e8<m>) * 23.0 + 1.0) |> int)
    for a in asteroids do
        do set_cursor_on_body a
        do Console.Write(a.Name)
    do Thread.Sleep(100)

let simulation() =
    let rec simulation m =
        do print_scene m
        let m' = simulation_step m
        do simulation m'
    do simulation f0
命名空间游戏
模块第3章=
开放系统
开放系统。线程
开放游戏,数学
类型小行星=
{
位置:Vector2
速度:矢量2
质量:浮子
名称:string
}
设dt=60.0
设G=6.67e-11
让地球半径=6.37e6
让场大小=地球半径*60.0
设最大速度=2.3e4
假设地球质量=5.97e24
让月球的质量=7.35e22
让我们创建\u字段num\u小行星=
设lerp(x:float)(a:float)=x*a+y*(1.0-a)
设rand=Random()
[
对于i=1到num_小行星
设m=(lerp地球质量月球质量(rand.NextDouble())*1.0e-4
设x=lerp 0.0字段大小(rand.NextDouble())
设y=lerp 0.0字段大小(rand.NextDouble())
设vx=最大速度*(rand.NextDouble()*2.0-1.0)*0.1
设vy=最大速度*(rand.NextDouble()*2.0-1.0)*0.1
产量
{
位置={X=X;Y=Y}
速度={X=vx;Y=vy}
质量=m
Name=“a”
}
]
设f0=创建_字段20
let钳位(p:Vector2,v:Vector2)=
让p,v=
如果p.X<0.0,则
{p与X=0.0},{v与X=-v.X}
其他的
p、 五
让p,v=
如果p.X>字段大小,则
{p与X=field_size},{v与X=-v.X}
其他的
p、 五
让p,v=
如果p.Y<0.0,则
{p与Y=0.0},{v与Y=-v.Y}
其他的
p、 五
让p,v=
如果p.Y>字段大小,则
{p with Y=field_size},{v with Y=-v.Y}
其他的
p、 五
p、 五
让力(a:小行星,a:小行星)=
设dir=a'.位置-a.位置
设距离=方向长度+1.0
G*a.质量*a.质量*dir/(距离*dist*dist*dist)
让模拟_步骤(小行星:小行星列表)=
[
对于一个在小行星吗
让力量=
[
对于一个'在小行星吗
如果是a,那么
屈服力(a,a’)
]    
设F=List.sum力
设p',v'=夹具(a位置,a速度)
产量
{
与
位置=p'+dt*v'
速度=v'+dt*F/a.质量
}
]
让我们打印场景(小行星:小行星列表)=
执行控制台清除()
对于i=0到79 do
Console.SetCursorPosition(i,0)
控制台。写入(“*”)
控制台.设置光标位置(i,23)
控制台。写入(“*”)
对于j=0到23 do
控制台。设置光标位置(0,j)
控制台。写入(“*”)
控制台.设置光标位置(79,j)
控制台。写入(“*”)
让我们在主体b上设置光标=
Console.SetCursorPosition(
((b.Position.X/4.0e8)*78.0+1.0)|>int,
((b.Position.Y/4.0e8)*23.0+1.0)|>int)
对于一个在小行星吗
是否在主体a上设置光标
do Console.Write(a.Name)
做线程。睡眠(100)
let simulation()=
让rec模拟m=
不要打印场景
设m'=模拟步骤m
做我的
进行模拟f0
数学模块代码:

namespace Games

module Math =
[<Measure>]
type m //metres

[<Measure>]
type kg //kilogram

[<Measure>]
type s // seconds

[<Measure>]
type N = kg*m/s^2 //Newtons

type Vector2<[<Measure>]'T> =
    {
        X : float<'T>
        Y : float<'T>
    }

    static member Zero : Vector2<'T> =
        { X = 0.0<_>; Y = 0.0<_> }

    static member (+) (v1:Vector2<'T>, v2:Vector2<'T>) : Vector2<'T> =
        { X = v1.X + v2.X; Y = v1.Y + v2.Y }

    static member (+) (v:Vector2<'T>, k:float<'T>) : Vector2<'T> =
        { X = v.X + k; Y = v.Y + k }

    static member (+) (k:float<'T>, v:Vector2<'T>) : Vector2<'T> = v + k

    static member (~-) (v:Vector2<'T>) : Vector2<'T> =
        { X = -v.X; Y = -v.Y }

    static member (-) (v1:Vector2<'T>, v2:Vector2<'T>) : Vector2<'T> =
        v1 + (-v2)

    static member (-) (v:Vector2<'T>, k:float<'T>) : Vector2<'T> =
        v + (-k)

    static member (-) (k:float<'T>, v:Vector2<'T>) : Vector2<'T> =
        k + (-v)

    static member (*) (v1:Vector2<'a>, v2:Vector2<'b>) : Vector2<'a * 'b> =
        { X = v1.X * v2.X; Y = v1.Y * v2.Y }

    static member (*) (v:Vector2<'a>, f:float<'b>) : Vector2<'a * 'b> =
        { X = v.X * f; Y = v.Y * f }

    static member (*) (f:float<'b>, v:Vector2<'a>) : Vector2<'b * 'a> =
        { X = f * v.X; Y = f * v.Y }

    static member (/) (v:Vector2<'a>, f:float<'b>) : Vector2<'a / 'b> =
        v * (1.0/f)

    member this.Length : float<'a> =
        sqrt((this.X * this.X + this.Y * this.Y))

    static member Distance(v1:Vector2<'T>, v2:Vector2<'T>) =
        (v1 - v2).Length

    static member Normalize(v:Vector2<'T>) : Vector2<1> = 
        v / v.Length
命名空间游戏
模块数学=
[]
m型//米
[]
类型kg//kg
[]
键入s//seconds
[]
类型N=kg*m/s^2//牛顿
类型向量2
Y:浮子=
{X=0.0;Y=0.0}
静态成员(+)(v1:Vector2):Vector2,k:浮点=
{X=v.X+k;Y=v.Y+k}
静态成员(+)(k:float):Vector2:Vector2,v2:Vector2=
v1+(-v2)
静态成员(-)(v:Vector2):Vector2,v:Vector2=
k+(-v)
静态成员(*)(v1:Vector2):Vector2=
{X=v1.X*v2.X;Y=v1.Y*v2.Y}
静态成员(*)(v:Vector2):Vector2=
{X=v.X*f;Y=v.Y*f}
静态成员(*)(f:float):向量2=
{X=f*v.X;Y=f*v.Y}
静态成员(/)(v:Vector2):Vector2=
v*(1.0/f)
此成员。长度:float,v2:Vector2):Vector2=
v/v.长度
要运行的代码示例:

[<EntryPoint>]
let main argv = 
    Games.Chapter3.simulation()
    0 // return an integer exit code
[]
让主argv=
游戏。第三章。模拟()
0//返回整数退出代码
有人能用VS2013和F#3.1/.Net4.5解释一下发生了什么吗

多谢各位


Mick

它认为您遇到了F#编译器错误。它出现在F#3.1.2及更早版本中,但此后已被修复,因此在4.0及更高版本中可以使用

根据问题讨论,在F#3.0及更早版本中,存在该缺陷,但并不总是导致运行时崩溃。看看这本书的示例代码项目,我猜作者使用F#3.0或更早版本编写了这些示例,但没有意识到它们触发了bug

解决办法:

  • 在发布模式下编译(启用优化),codegen应该是正确的(假设这确实是同一个问题)
  • 尝试使用F#4.0预发行版(通过或仅从中获取F#位)

提供缺少的定义,代码对我来说运行良好(在linux中使用fsi)。可能错误来自其他地方?使用更新的定义仍然不会产生错误。请提供一个简单的代码示例,可以剪切、粘贴并运行,从而产生错误