对象、值和指针
Felix支持函数式和命令式编程风格。这些模型之间的关键桥梁是指针。
Felix中的数组是一个不可变的值,它不能被修改为一个值。但是数组可以存储在变量中,变量是对象的名称。一个对象有两个重要的含义:它命名一个存储位置,也引用位于该存储中的值。
在Felix中,变量的名称表示存储的值,而应用于变量名的所谓address of operator表示位置:
var x = 1,2,3,4; //1: x is an array value, and ..
var px = &x; //2: it also denotes addressable store
var y = *px; //3: y is a copy of x
px <- 5,6,7,8; //4: x now stores a new array
这段代码演示了如何在第2行获取变量的地址,如何在第3行的地址获取值,如何在第4行中修改地址处的值。
前缀符号 & 有时称为地址运算符,但它不是运算符!相反,这只是一种指定我们想要变量所表示的存储地址的方法,而不是存储在那里的值,后者由普通变量名表示。
地址是一个叫做指针类型的Felix数据类型。如果一个变量存储了一个T类型的值,则指针用类型&T表示。
在第3行中,我们使用所谓的解引用操作符prefix * ,表示指针指向的存储中保存的值。解引用是一个真正的算子。
在第4行中,我们使用中缀左箭头运算符,它被称为 store-at ,用于将右手参数值存储在左手指针值表示的位置。
新操作员
Felix也提供了前缀 new 运算符,它将值复制到堆并返回指向它的指针。
var px = new 42;
var x = *px; // x is 42
px <- 43; // px now points to 43
这是另一种获取对象指针的方法,它允许替换或修改存储的值。
指针投影
所有产品类型(包括数组、元组、记录和结构)都提供值投影,用于获取部分值,这些部分称为组件:
var ax = 1,2,3,4; // array
var ax1 = ax.1; // apply projection 1 to get value 2
var tx = 1, "hello", 42.0; // tuple
var tx1 = tx.1; // apply projection 1 to get value "hello"
var rx = (a=1, b="hello", c=42.0); // record
var rx1 = rx.b; // apply projection b to get value "hello"
struct X {
a:int;
b:string;
c:double;
}
var sx = X (1, "hello", 42.0); // struct
var sx1 = sx.b; // apply projection b to get value "hello"
数组和元组有编号的组件,因此通过编号的投影访问,记录和结构具有命名组件,因此值由命名投影访问。
虽然这里的指标是数字和名称,但值预测是一类函数。功能及其类型分别为:
proj 1: int^4 -> int
proj 1: int * string * double -> string
b: (a:int, b:string, c:double) -> string
b: X -> string
这些都是价值预测。要在产品类型的组件中存储值,必须首先获取指向该值所在存储区的指针,然后应用 指针投影 获取指向组件存储的指针。然后,我们可以使用store at过程来设置该组件,而不使用产品的其余部分:
&ax . 1 <- 42; // array
&tx . 1 <- "world"; // tuple
&rx . b <- "world"; // record
&sx . b <- "world"; // struct
在每种情况下,我们使用相同的投影索引,一个数字或一个名称,作为值投影,但是投影是重载的,因此它们也可以用于指针。这些指针投影是一类函数,其类型分别如下:
proj 1: &(int^4) -> &int
proj 1: &(int * string * double) -> &string
b: &(a:int, b:string, c:double) -> &string
b: &X -> &string
需要注意的是指针是值,指针投影是第一类纯函数函数。不像C和C++,没有LoValor或引用的概念。storeat操作符是一个过程,因此它被用于命令式代码中,但是决定存储在哪里的计算纯粹是功能性的。
程序员应该注意,C地址算法也是纯函数的,但是,C没有任何类型良好的方法来计算除数组之外的产品组件:您只需使用 offsetof 宏和强制转换。
C++有指向成员的指针,但是微积分是不完整的,它们不能一起添加!
在Felix中,投影是函数,所以在产品中添加组件偏移量只是函数组合!