最近對(duì)S
語(yǔ)言比較感興趣舟陆,于是開(kāi)始學(xué)習(xí)S
語(yǔ)言坠非,相當(dāng)于是對(duì)于R
語(yǔ)言的一個(gè)補(bǔ)充
S語(yǔ)言的知識(shí)
變量和函數(shù)
S語(yǔ)言的變量可以用variable
直接進(jìn)行定義敏沉,例如
variable x,y,z;
S語(yǔ)言的變量不需要提前聲明,通過(guò)等式可以直接定義,例如
x=3
,y=sin(5.6)
,z="I think, therefore i am"
S語(yǔ)言的函數(shù)可以用define
直接進(jìn)行定義盟迟,例如
define compute_average (x,y) { variable s =x +y; return s/2.0 }
qualifier
通過(guò)qualifier
為一個(gè)函數(shù)增加修飾成分秋泳,例如
define plot (x, y) { variable linestyle = qualifier ("linestyle", "solid"); variable color = qualifier ("color", "black"); sys_set_color (color); sys_set_linestyle (linestyle); sys_plot (x,y); }
其中linestyle
和color
是修飾成分
strings
S語(yǔ)言可以對(duì)字符操作,而不考慮給字符分配內(nèi)存空間攒菠,其中strcat
可以用+
代替迫皱,例如:
define concat_3_strings (a, b, c) { return strcat (a, b, c); }
在相同情況下,C語(yǔ)言需要寫(xiě)下面的語(yǔ)句:
char *concat_3_strings (char *a, char *b, char *c) { unsigned int len; char *result; len = strlen (a) + strlen (b) + strlen (c); if (NULL == (result = (char *) malloc (len + 1))) exit (1); strcpy (result, a); strcat (result, b); strcat (result, c); return result; }
Referencing and Dereferencing
和其他大多數(shù)語(yǔ)言一樣辖众,用&
可以用來(lái)應(yīng)用其他object
或者是function
卓起,例如:
define compute_functional_sum (funct) { variable i, s; s = 0; for (i = 0; i < 10; i++) { s += (@funct)(i); } return s; } variable sin_sum = compute_functional_sum (&sin); variable cos_sum = compute_functional_sum (&cos);
解引用,用符號(hào)@
凹炸,類似于C語(yǔ)言中的指針戏阅,例如:
define set_xyz (x, y, z) { @x = 1; @y = 2; @z = 3; } variable X, Y, Z; set_xyz (&X, &Y, &Z);
其中C語(yǔ)言的樣式
void set_xyz (int *x, int *y, int *z) { *x = 1; *y = 2; *z = 3; }
Arrays
S語(yǔ)言支持多維數(shù)組,例如:
variable A = Int_Type [10]; # 創(chuàng)建10個(gè)整數(shù)的一維數(shù)組 variable B = Int_Type [10, 3]; # 創(chuàng)建10*3整數(shù)的二維數(shù)組 variable C = [1, 3, 5, 7, 9]; #直接生成數(shù)組 variable D=[1:9:2]; #創(chuàng)建以2為間距啤它,從1到9的數(shù)組 variable E=[0:1:#1000]奕筐; #創(chuàng)建1000個(gè)0到1的浮點(diǎn)數(shù)
Arrays類型變量可以直接在函數(shù)中使用:
define init_array (a) { variable i, imax; imax = length (a); for (i = 0; i < imax; i++) { a[i] = 7; } } variable A = Int_Type [10]; init_array (A);
Arrays的類型
- Double_Type : double
- Complex_Type: complex
- String_Type : string
- Ref_Type : reference
- Any_Type
S語(yǔ)言與C語(yǔ)言之間的對(duì)比
variable X, Y; X = [0:2*PI:0.01]; Y = 20 * sin (X);
double *X, *Y; unsigned int i, n; n = (2 * PI) / 0.01 + 1; X = (double *) malloc (n * sizeof (double)); Y = (double *) malloc (n * sizeof (double)); for (i = 0; i < n; i++) { X[i] = i * 0.01; Y[i] = 20 * sin (X[i]); }
Lists
List類型與array相似,但是List類型中的元素可以不同
struct
與C相似的是变骡,S語(yǔ)言之中也有結(jié)構(gòu)體
variable person = struct { first_name, last_name, age }; variable bill = @person; bill.first_name = "Bill"; bill.last_name = "Clinton"; bill.age = 51;
一般直接用typedef
來(lái)直接定義結(jié)構(gòu)體
typedef struct { first_name, last_name, age } Person_Type; variable bill = @Person_Type; bill.first_name = "Bill"; bill.last_name = "Clinton"; bill.age = 51;
定義的結(jié)構(gòu)體可以直接生成array類型的結(jié)構(gòu)體离赫,如下所示:
People = Person_Type [100]; People[0].first_name = "Bill"; People[1].first_name = "Hillary";
對(duì)于結(jié)構(gòu)體類型,可以直接用Struct_Type
來(lái)定義:
People = Struct_Type [100]; People[0] = @person; People[0].first_name = "Bill"; People[1] = @person; People[1].first_name = "Hillary";
結(jié)構(gòu)體初始化函數(shù)
可以用下面的代碼進(jìn)行初始化
define create_person (first, last, age) { variable person = @Person_Type; person.first_name = first; person.last_name = last; person.age = age; return person; } variable Bill = create_person ("Bill", "Clinton", 51);
后綴(suffixes)
- R:反斜杠線不會(huì)被轉(zhuǎn)義
- Q:反斜杠線會(huì)被轉(zhuǎn)義
- B:字符串將會(huì)被翻譯成二進(jìn)制字符串
- $:將字符串中的變量讀出
以下句子表達(dá)同一個(gè)意思
file = "C:\\windows\\apps\\slrn.rc"; file = "C:\\windows\\apps\\slrn.rc"Q; file = "C:\windows\apps\slrn.rc"R; file =
C:\windows\apps\slrn.rc; % slang-2.2 and above
Null_Type
define add_numbers (a, b) { if (a == NULL) a = 0; if (b == NULL) b = 0; return a + b; } variable c = add_numbers (1, 2); variable d = add_numbers (1, NULL); variable e = add_numbers (1,); variable f = add_numbers (,);
Ref_Type
sin_ref = &sin; y = (@sin_ref) (1.0);
其他容器類型
- Array_Type
- Assoc_Type
- List_Type
- Struct_Type
DataType_Type
對(duì)于數(shù)據(jù)類型塌碌,S語(yǔ)言中有很多類型
類型 | 表達(dá)式 |
---|---|
signed character | Char_Type |
unsigned character | UChar_Type |
short integer | Short_Type |
unsigned short integer | UShort_Type |
Plain integer | Integer_Type |
plain unsigned integer | UInteger_Type |
long integer | Long_Type |
unsigned long integer | ULong_Type |
long long integer | LLong_Type |
single precision real | Float_Type |
double precision rea | Double_Type |
complex numbers | Complex_Type |
strings,C strings | String_Type |
binary strings | BString_Type |
structures | Struct_Type |
references | Ref_Type |
NULL | Null_Type |
Arrays | Array_Type |
associative arrays/hashes | Assoc_Type |
Lists | List_Type |
DataType | DataType_Type |
數(shù)據(jù)類型的轉(zhuǎn)換
對(duì)于數(shù)據(jù)類型的轉(zhuǎn)換互捌,S語(yǔ)言可以用typecast
進(jìn)行轉(zhuǎn)換
variable x=10,y; y=typecast (x, Double_Type);
Statement
一般來(lái)說(shuō)虽缕,statement
一般是由expressions
組成
function
編譯器中含有兩種函數(shù):intrinsic functions
和slang functions
经伙,函數(shù)的聲明形式:
define function-name (parameter-list ) { statement-list }
函數(shù)得引用與解引用:
define derivative (f, x) { variable h = 1e-6; return ((@f)(x+h) - (@f)(x)) / h; } define x_squared (x) { return x^2; } dydx = derivative (&x_squared, 3);
對(duì)于S語(yǔ)言中的函數(shù)拘荡,可以先不指定輸入?yún)?shù),在函數(shù)中可增加輸入?yún)?shù):
define add_10 () { variable x; x = (); return x + 10; } variable s = add_10 (12); % ==> s = 22;
所以函數(shù)也可以這么定義:
define function_name () { variable x, y, ..., z; z = (); . . y = (); x = (); . . }
平均數(shù)的求法:
define average_n (n) { variable s, x; s = 0; loop (n) { x = (); % get next value from stack s += x; } return s / n; }
如果不知道輸入數(shù)據(jù)的多少频丘,可以用_NARGS
來(lái)查看:
define average_n () { variable x, s = 0; if (_NARGS == 0) usage ("ave = average_n (x, ...);"); loop (_NARGS) { x = (); s += x; } return s / _NARGS; }
其中EXIT_BLOCK
NameSpace
其中Namespace
的變量類型有private
,public
和static
办成,在namespace中增加foo.sl
:
evalfile("foo.sl","foo")
% foo.sl variable X = 1; variable Y; private variable Z; public define set_Y (y) { Y = y; } define set_z (z) { Z = z; }
Arrays
直接通過(guò)Array_Type
來(lái)定義數(shù)組:
variable a = @Array_Type (data-type , integer-array );
有時(shí)候?yàn)榱藢⒁痪S的數(shù)組重構(gòu),變成二維的數(shù)組搂漠,可以用reshape
函數(shù)進(jìn)行變換:
reshape (array-name, integer-array)
舉個(gè)例子來(lái)說(shuō):
varaible a = Double_Type [100]; reshape(a, [10, 10];
_reshape
類似于reshape
函數(shù),它會(huì)創(chuàng)建一個(gè)新的數(shù)組某弦,而不是改變?cè)袛?shù)組的形狀
Associative Arrays
S語(yǔ)言中Assoc_Type
類型與C++
中的vector
類型比較相似桐汤,也有點(diǎn)類似于Python
中的字典
創(chuàng)建Assoc_Type
類型變量,可以用以下聲明:
Assoc_Type [type ]; Assoc_Type [type , default-value ] ; Assoc_Type []
A = Assoc_Type [Int_Type]; A["alpha"] = 1; A["beta"] = 2; A["gamma"] = 3;
當(dāng)Type
沒(méi)有指定的時(shí)候靶壮,它可以儲(chǔ)存任何類型的變量怔毛。
對(duì)于associative arrays
,有以下幾種函數(shù)對(duì)其進(jìn)行操作:
-
assoc_get_keys
: 返回 keys of the array -
assoc_get_values
:返回 values of the array -
assoc_key_exists
:是否存在該 key -
assoc_delete_key
: 刪除該key
一個(gè)計(jì)算詞頻的程序:
a = Assoc_Type [Int_Type]; foreach word (word_list) { if (0 == assoc_key_exists (a, word)) a[word] = 0; a[word]++; % same as a[word] = a[word] + 1; }
Structures and User-Defined Types
結(jié)構(gòu)體定義:
t = @Struct_Type ("city_name", "population", "next"); t = @Struct_Type (["city_name", "population", "next"]);
對(duì)于結(jié)構(gòu)體中的元素腾降,可以使用dot
來(lái)訪問(wèn).
Linked Lists
通過(guò)在結(jié)構(gòu)體中增加next
t = struct { city_name, population, next };
其中可以用下面函數(shù):
define create_population_list () { variable city_name, population, list_root, list_tail; variable next; list_root = NULL; while (read_next_city (&city_name, &population)) { next = struct {city_name, population, next }; next.city_name = city_name; next.population = population; next.next = NULL; if (list_root == NULL) list_root = next; else list_tail.next = next; list_tail = next; } return list_root;
使用typedef
可以定義新的類型
操作符的重載
使用__add_binary
可以進(jìn)行操作符的重載拣度,例如:
- 定義結(jié)構(gòu)體
typedef struct { x, y, z } Vector_Type;
- 定義初始化
define vector_new (x, y, z) { variable v = @Vector_Type; v.x = double(x); v.y = double(y); v.z = double(z); return v; }
- 定義加的操作
define vector_add (v1, v2) { return vector_new (v1.x+v2.x, v1.y+v2.y, v1.z+v2.z); }
- 對(duì)變量進(jìn)行操作
V1 = vector_new (2,3,4); V2 = vector_new (6,2,1); V3 = vector_new (-3,1,-6); V4 = vector_add (V1, vector_add (V2, V3));
但是有時(shí)候,我們想直接用+
進(jìn)行表示,這個(gè)時(shí)候可以用__add_binary
來(lái)定義:
__add_binary (op , result-type , funct , typeA ,typeB );
例如:
define vector_minus (v1, v2) { return vector_new (v1.x-v2.x, v1.y-v2.y, v1.z-v2.z); } __add_binary ("-", Vector_Type, &vector_minus, Vector_Type, Vector_Type); define vector_eqs (v1, v2) { return (v1.x==v2.x) and (v1.y==v2.y) and (v1.z==v2.z); } __add_binary ("==", Char_Type, &vector_eqs, Vector_Type, Vector_Type);
Lists
對(duì)于列表的操作抗果,可以用list_insert
和list_append
進(jìn)行操作筋帖,例如
list_insert(list,obj,nth)
和list_append(list,obj,nth)
也可以直接使用list = {"hi", list};
在頭部增加元素,list_delete(list,2)
即可以刪除list中的一個(gè)元素冤馏。
list_pop
與list_delete
不同的地方在于,list_pop
返回的是list
的元素日麸。
debug過(guò)程
exit
if (-1 == write_to_file ("/tmp/foo", "bar")) { () = fprintf (stderr, "Write failed\n"); exit (1); }
Exceptions
define write_to_file (file, str) { variable fp = fopen (file, "w"); if (fp == NULL) throw OpenError; if (-1 == fputs (str, fp)) throw WriteError; if (-1 == fclose (fp)) throw WriteError; }
try-catch
try { write_to_file ("/tmp/foo", "bar"); } catch OpenError: { message ("*** Warning: failed to open /tmp/foo."); } next_statement;
error的類型
AnyError OSError MallocError ImportError ParseError SyntaxError DuplicateDefinitionError UndefinedNameError RunTimeError InvalidParmError TypeMismatchError UserBreakError StackError StackOverflowError StackUnderflowError ReadOnlyError VariableUnitializedError NumArgsError IndexError UsageError ApplicationError InternalError NotImplementedError LimitExceededError MathError DivideByZeroError ArithOverflowError ArithUnderflowError DomainError IOError WriteError ReadError OpenError DataError UnicodeError InvalidUTF8Error UnknownError
對(duì)于新建的error
類型
new_exception (exception-name , baseclass , description );
文件操作
loading files: evalfile
,autoload
and require
模塊module
通過(guò)import
來(lái)引入模塊,例如import ("pcre");
更好的是使用require
來(lái)引入模塊逮光,例如require ("pcre");
與C語(yǔ)言的域操作::
不同的是代箭,S語(yǔ)言中的域操作是->
S語(yǔ)言中的文件操作
- fopen: 打開(kāi)文件
- fclose:關(guān)閉文件
- fgets:讀取文件中的一行
- fputs:寫(xiě)入文件
- fprintf: 向文件中寫(xiě)入格式文本
- fwrite: 向文件中寫(xiě)入對(duì)象
- fread: 讀取文件若干行
- fread_bytes:以二進(jìn)制的格式讀取文件
- feof: 是否在文件的結(jié)尾
- ferror: 檢查是否有錯(cuò)誤
- clearerr: 清除文件讀入流中的錯(cuò)誤
- fflush: 將緩存區(qū)文件讀出
- ftell: 讀取當(dāng)前文件讀取位置
- fseek: 設(shè)置文件位置
- fgetslines: 讀取文件若干行
例子如下:
define count_lines_in_file (file) { variable fp, line, count; fp = fopen (file, "r"); % Open the file for reading if (fp == NULL) throw OpenError, "$file failed to open"$; count = 0; while (-1 != fgets (&line, fp)) count++; () = fclose (fp); return count; }