F#cons运算符和类中的列表

时间:2015-12-17 17:15:32

标签: f#

所以这是我的问题。我有一个非常功能的python项目......但是它基本上是用类运行的......所以F#似乎是我的代码编译版本的理想语言(我想黑盒子我的源代码...... python代码只是坐在文件中。不酷。)

在我的python类中,我有一个通用容器 - 一个python列表。此容器将包含给定实现中的统一长度的数组...

这是我的问题:我需要在初始化后将数组添加到列表中。

将数组添加到类中的列表的正确方法是什么?

这就是我所拥有的...但似乎它会很慢,因为它会抛出一个新副本的旧列表(对吧??):

 type myclass() = 
     let mutable _training = []
     member this.training with get() = _training
                          and set(value) = _training <- value::_training

然而,这失败即使在下面建议的修改之后),因为编译器声称set函数是obj with set而不是obj list with set一个_training,即使它承认<-是设置函数中sortBy左侧的可变obj列表......我很难过。

这样做的正确“F#”方法是什么?

2 个答案:

答案 0 :(得分:3)

正确的&#39; F#的方法是根本没有myclass。具有单个getter和setter的类不会为不可变列表提供任何值。

尽管如此,上面的代码并没有因为多种原因而编译:

  1. type定义为=,而不是:
  2. _training不受let表达式约束。
  3. 如果您要改变_training值,则必须声明let mutable
  4. 即便如此,get的返回值为obj list,但set(符号value)的输入值为obj,因为使用了cons运算符(::)。正如编译器所说,getset的类型必须相同。
  5. 您可以通过解决所有这些问题进行编译:

    type Myclass() =
         let mutable _training = []
         member this.training with get() = _training
                              and set(value) = _training <- value
    

    但它什么都不会做。如果需要列表,则传递列表。并不是我们不相信F#中的封装,而是properties aren't equivalent to encapsulation anyway ......

    顺便说一下,使用Pascal Case命名类型是惯用的,所以MyClass而不是myclass。领先的下划线也没有被使用,所以它应该是training而不是_training

答案 1 :(得分:2)

问题是属性有类型, 并且getter和setter必须与该类型兼容。

如果我以交互方式运行您的代码,编译器会帮助我确切地告诉我!

type myclass() = 
     let mutable _training = []
     member this.training 
        with get() = _training
        and set(value) = _training <- value::_training
// error FS3172: A property's getter and setter must have the same type. 
// Property 'training' has getter of type 'obj list' 
// but setter of type 'obj'.

答案很简单,就是要有一个不同的方法来预先添加一个元素 到列表中:

type myclass() = 
     let mutable _training = []
     member this.training 
        with get() = _training
        and set(newTraining) = _training <- newTraining

     member this.prepend(element) = 
        _training <- (element::_training)

     member this.prependList(list) = 
        _training <- (list @ _training)

// test
let myList = myclass() 
myList.prepend(1)
myList.prepend(2)
myList.training  // output => [2; 1]

myList.prependList([3;4])
myList.training  // output => [3; 4; 2; 1]

从功能的角度来看,它不是一个很好的实现, 但它确实回答了你的问题。

请注意,如果您确实需要纯功能实现, 你根本不需要上课。

// test
let myList = []
let myList2 = 1::myList 
let myList3 = 2::myList2 
// myList3 => [2; 1]

let myList4 = [3;4] @ myList3
// myList4 => [3; 4; 2; 1]

现在,如何以一种不错的方式使用不可变状态 - 这是一个整体 其他问题! :)