
函數語言程式設計 - 快速指南
函數語言程式設計 - 簡介
函數語言程式設計語言專門設計用於處理符號計算和列表處理應用程式。函數語言程式設計基於數學函式。一些流行的函數語言程式設計語言包括:Lisp、Python、Erlang、Haskell、Clojure等。
函數語言程式設計語言分為兩類,即:
純函式式語言 - 這些型別的函式式語言僅支援函式式正規化。例如 - Haskell。
非純函式式語言 - 這些型別的函式式語言支援函式式正規化和指令式程式設計風格。例如 - LISP。
函數語言程式設計 - 特點
函數語言程式設計最突出的特點如下:
函數語言程式設計語言設計在數學函式的概念上,使用條件表示式和遞迴來執行計算。
函數語言程式設計支援高階函式和惰性求值特性。
函數語言程式設計語言不支援像迴圈語句和條件語句(如If-Else和Switch語句)這樣的流程控制。它們直接使用函式和函式呼叫。
與OOP一樣,函數語言程式設計語言支援抽象、封裝、繼承和多型等流行概念。
函數語言程式設計 - 優點
函數語言程式設計提供了以下優點:
無錯誤程式碼 - 函數語言程式設計不支援狀態,因此沒有副作用結果,我們可以編寫無錯誤的程式碼。
高效的並行程式設計 - 函數語言程式設計語言沒有可變狀態,因此沒有狀態更改問題。可以將“函式”程式設計為並行執行的“指令”。此類程式碼支援易於重用和可測試性。
效率 - 函式式程式由可以併發執行的獨立單元組成。因此,此類程式效率更高。
支援巢狀函式 - 函數語言程式設計支援巢狀函式。
惰性求值 - 函數語言程式設計支援惰性函式構造,如惰性列表、惰性對映等。
不利的一面是,函數語言程式設計需要大量的記憶體空間。因為它沒有狀態,所以每次執行操作都需要建立新的物件。
函數語言程式設計用於需要對同一組資料執行大量不同操作的情況。
Lisp用於人工智慧應用,如機器學習、語言處理、語音和視覺建模等。
嵌入式Lisp直譯器為某些系統(如Emacs)添加了可程式設計性。
函數語言程式設計與面向物件程式設計
下表突出顯示了函數語言程式設計和麵向物件程式設計之間的主要區別:
函數語言程式設計 | OOP |
---|---|
使用不可變資料。 | 使用可變資料。 |
遵循宣告式程式設計模型。 | 遵循指令式程式設計模型。 |
重點在於:“你在做什麼” | 重點在於“你如何去做” |
支援並行程式設計 | 不適合並行程式設計 |
其函式沒有副作用 | 其方法可能會產生嚴重的副作用。 |
流程控制透過函式呼叫和帶遞迴的函式呼叫完成 | 流程控制透過迴圈和條件語句完成。 |
它使用“遞迴”概念來迭代集合資料。 | 它使用“迴圈”概念來迭代集合資料。例如:Java中的For-each迴圈 |
語句的執行順序不那麼重要。 | 語句的執行順序非常重要。 |
支援“資料抽象”和“行為抽象”。 | 僅支援“資料抽象”。 |
程式程式碼的效率
程式程式碼的效率與演算法效率和執行速度成正比。良好的效率確保更高的效能。
影響程式效率的因素包括:
- 機器的速度
- 編譯器速度
- 作業系統
- 選擇合適的程式語言
- 程式中資料組織的方式
- 用於解決問題的演算法
可以透過執行以下任務來提高程式語言的效率:
透過刪除不必要的程式碼或導致冗餘處理的程式碼。
透過利用最佳記憶體和非易失性儲存
透過在任何適用的地方使用可重用元件。
透過在程式的所有層中使用錯誤和異常處理。
透過建立確保資料完整性和一致性的程式程式碼。
透過開發符合設計邏輯和流程的程式程式碼。
高效的程式程式碼可以最大程度地減少資源消耗和完成時間,同時最大程度地降低對操作環境的風險。
函式概述
在程式設計方面,函式是一塊執行特定任務的語句塊。函式接受資料,處理資料並返回結果。編寫函式的主要目的是支援可重用性的概念。編寫函式後,可以輕鬆呼叫它,而無需一遍又一遍地編寫相同的程式碼。
不同的函式式語言使用不同的語法來編寫函式。
編寫函式的先決條件
在編寫函式之前,程式設計師必須瞭解以下幾點:
程式設計師應該知道函式的目的。
程式設計師應該知道函式的演算法。
程式設計師應該知道函式資料變數及其目標。
程式設計師應該知道使用者呼叫的函式的資料。
函式的流程控制
當函式被“呼叫”時,程式“轉移”控制以執行函式,其“控制流”如下:
程式到達包含“函式呼叫”的語句。
執行函式內的第一行。
從上到下執行函式內的所有語句。
當函式成功執行後,控制權返回到其開始執行的語句。
函式計算和返回的任何資料都將用於替換原始程式碼行中的函式。
函式的語法
函式的一般語法如下:
returnType functionName(type1 argument1, type2 argument2, . . . ) { // function body }
在C++中定義函式
讓我們舉個例子來了解如何在C++(一種面向物件程式語言)中定義函式。以下程式碼包含一個新增兩個數字並將其結果作為輸出提供的函式。
#include <stdio.h> int addNum(int a, int b); // function prototype int main() { int sum; sum = addNum(5,6); // function call printf("sum = %d",sum); return 0; } int addNum (int a,int b) { // function definition int result; result = a + b; return result; // return statement }
它將產生以下輸出:
Sum = 11
在Erlang中定義函式
讓我們看看如何在Erlang(一種函數語言程式設計語言)中定義相同的函式。
-module(helloworld). -export([add/2,start/0]). add(A,B) -> C = A + B, io:fwrite("~w~n",[C]). start() -> add(5,6).
它將產生以下輸出:
11
函式原型
函式原型是函式的宣告,包括返回型別、函式名和引數列表。它類似於沒有函式體的函式定義。
例如 - 一些程式語言支援函式原型,而一些不支援。
在C++中,我們可以像這樣建立函式'sum'的函式原型:
int sum(int a, int b)
注意 - Python、Erlang等程式語言不支援函式原型,我們需要宣告完整的函式。
函式原型的作用是什麼?
當呼叫函式時,編譯器會使用函式原型。編譯器使用它來確保正確的返回型別、傳遞的引數列表正確以及它們的返回型別正確。
函式簽名
函式簽名類似於函式原型,其中引數的數量、引數的資料型別和出現的順序應按相同的順序排列。例如:
void Sum(int a, int b, int c); // function 1 void Sum(float a, float b, float c); // function 2 void Sum(float a, float b, float c); // function 3
Function1和Function2具有不同的簽名。Function2和Function3具有相同的簽名。
注意 - 我們將在後續章節中討論的函式過載和函式重寫基於函式簽名的概念。
當一個類有多個名稱相同但簽名不同的函式時,函式過載是可能的。
當派生類函式與基類具有相同的名稱和簽名時,函式重寫是可能的。
函數語言程式設計 - 函式型別
函式分為兩種型別:
- 預定義函式
- 使用者定義函式
在本章中,我們將詳細討論函式。
預定義函式
這些是內置於語言中用於執行操作的函式,並存儲在標準函式庫中。
例如 - C++中的'Strcat'和Haskell中的'concat'用於追加兩個字串,C++中的'strlen'和Python中的'len'用於計算字串長度。
在C++中列印字串長度的程式
以下程式演示瞭如何使用C++列印字串的長度:
#include <iostream> #include <string.h> #include <stdio.h> using namespace std; int main() { char str[20] = "Hello World"; int len; len = strlen(str); cout<<"String length is: "<<len; return 0; }
它將產生以下輸出:
String length is: 11
在Python中列印字串長度的程式
以下程式演示瞭如何使用Python(一種函數語言程式設計語言)列印字串的長度:
str = "Hello World"; print("String length is: ", len(str))
它將產生以下輸出:
('String length is: ', 11)
使用者定義函式
使用者定義函式由使用者定義以執行特定任務。有四種不同的模式來定義函式:
- 沒有引數且沒有返回值的函式
- 沒有引數但有返回值的函式
- 有引數但沒有返回值的函式
- 有引數且有返回值的函式
沒有引數且沒有返回值的函式
以下程式演示瞭如何在C++中定義一個沒有引數且沒有返回值的函式:
#include <iostream> using namespace std; void function1() { cout <<"Hello World"; } int main() { function1(); return 0; }
它將產生以下輸出:
Hello World
以下程式演示瞭如何在Python中定義一個類似的函式(沒有引數且沒有返回值):
def function1(): print ("Hello World") function1()
它將產生以下輸出:
Hello World
沒有引數但有返回值的函式
以下程式演示瞭如何在C++中定義一個沒有引數但有返回值的函式:
#include <iostream> using namespace std; string function1() { return("Hello World"); } int main() { cout<<function1(); return 0; }
它將產生以下輸出:
Hello World
以下程式演示瞭如何在Python中定義一個類似的函式(沒有引數但有返回值):
def function1(): return "Hello World" res = function1() print(res)
它將產生以下輸出:
Hello World
有引數但沒有返回值的函式
以下程式演示瞭如何在C++中定義一個有引數但沒有返回值的函式:
#include <iostream> using namespace std; void function1(int x, int y) { int c; c = x+y; cout<<"Sum is: "<<c; } int main() { function1(4,5); return 0; }
它將產生以下輸出:
Sum is: 9
以下程式演示瞭如何在Python中定義一個類似的函式:
def function1(x,y): c = x + y print("Sum is:",c) function1(4,5)
它將產生以下輸出:
('Sum is:', 9)
有引數且有返回值的函式
以下程式演示瞭如何在C++中定義一個沒有引數但有返回值的函式:
#include <iostream> using namespace std; int function1(int x, int y) { int c; c = x + y; return c; } int main() { int res; res = function1(4,5); cout<<"Sum is: "<<res; return 0; }
它將產生以下輸出:
Sum is: 9
以下程式演示瞭如何在Python中定義一個類似的函式(有引數且有返回值):
def function1(x,y): c = x + y return c res = function1(4,5) print("Sum is ",res)
它將產生以下輸出:
('Sum is ', 9)
函數語言程式設計 - 按值呼叫
定義函式後,我們需要向其中傳遞引數以獲得所需的輸出。大多數程式語言支援按值呼叫和按引用呼叫方法將引數傳遞給函式。
在本章中,我們將學習“按值呼叫”如何在面向物件程式語言(如C++)和函數語言程式設計語言(如Python)中工作。
在按值呼叫方法中,原始值不能更改。當我們將引數傳遞給函式時,函式引數會在棧記憶體中本地儲存它。因此,值僅在函式內部更改,並且不會對函式外部產生影響。
C++中的按值呼叫
以下程式演示了按值呼叫如何在C++中工作:
#include <iostream> using namespace std; void swap(int a, int b) { int temp; temp = a; a = b; b = temp; cout<<"\n"<<"value of a inside the function: "<<a; cout<<"\n"<<"value of b inside the function: "<<b; } int main() { int a = 50, b = 70; cout<<"value of a before sending to function: "<<a; cout<<"\n"<<"value of b before sending to function: "<<b; swap(a, b); // passing value to function cout<<"\n"<<"value of a after sending to function: "<<a; cout<<"\n"<<"value of b after sending to function: "<<b; return 0; }
它將產生以下輸出:
value of a before sending to function: 50 value of b before sending to function: 70 value of a inside the function: 70 value of b inside the function: 50 value of a after sending to function: 50 value of b after sending to function: 70
Python中的按值呼叫
以下程式演示了按值呼叫如何在Python中工作:
def swap(a,b): t = a; a = b; b = t; print "value of a inside the function: :",a print "value of b inside the function: ",b # Now we can call the swap function a = 50 b = 75 print "value of a before sending to function: ",a print "value of b before sending to function: ",b swap(a,b) print "value of a after sending to function: ", a print "value of b after sending to function: ",b
它將產生以下輸出:
value of a before sending to function: 50 value of b before sending to function: 75 value of a inside the function: : 75 value of b inside the function: 50 value of a after sending to function: 50 value of b after sending to function: 75
函數語言程式設計 - 按引用呼叫
在引用傳遞中,原始值會被改變,因為我們傳遞了引數的引用地址。實際引數和形式引數共享相同的地址空間,因此函式內部的任何值更改都會反映在函式內部和外部。
C++ 中的引用傳遞
以下程式演示了按值呼叫如何在C++中工作:
#include <iostream> using namespace std; void swap(int *a, int *b) { int temp; temp = *a; *a = *b; *b = temp; cout<<"\n"<<"value of a inside the function: "<<*a; cout<<"\n"<<"value of b inside the function: "<<*b; } int main() { int a = 50, b = 75; cout<<"\n"<<"value of a before sending to function: "<<a; cout<<"\n"<<"value of b before sending to function: "<<b; swap(&a, &b); // passing value to function cout<<"\n"<<"value of a after sending to function: "<<a; cout<<"\n"<<"value of b after sending to function: "<<b; return 0; }
它將產生以下輸出:
value of a before sending to function: 50 value of b before sending to function: 75 value of a inside the function: 75 value of b inside the function: 50 value of a after sending to function: 75 value of b after sending to function: 50
Python 中的引用傳遞
以下程式演示了按值呼叫如何在Python中工作:
def swap(a,b): t = a; a = b; b = t; print "value of a inside the function: :",a print "value of b inside the function: ",b return(a,b) # Now we can call swap function a = 50 b =75 print "value of a before sending to function: ",a print "value of b before sending to function: ",b x = swap(a,b) print "value of a after sending to function: ", x[0] print "value of b after sending to function: ",x[1]
它將產生以下輸出:
value of a before sending to function: 50 value of b before sending to function: 75 value of a inside the function: 75 value of b inside the function: 50 value of a after sending to function: 75 value of b after sending to function: 50
函式過載
當我們有多個函式名稱相同但引數不同的函式時,我們就說這些函式被過載了。此技術用於增強程式的可讀性。
過載函式有兩種方法,即 -
- 具有不同數量的引數
- 具有不同的引數型別
當我們需要對不同數量或型別的引數執行單個操作時,通常會進行函式過載。
C++ 中的函式過載
以下示例演示瞭如何在 C++(一種面向物件程式語言)中進行函式過載 -
#include <iostream> using namespace std; void addnum(int,int); void addnum(int,int,int); int main() { addnum (5,5); addnum (5,2,8); return 0; } void addnum (int x, int y) { cout<<"Integer number: "<<x+y<<endl; } void addnum (int x, int y, int z) { cout<<"Float number: "<<x+y+z<<endl; }
它將產生以下輸出:
Integer number: 10 Float number: 15
Erlang 中的函式過載
以下示例演示瞭如何在 Erlang(一種函數語言程式設計語言)中執行函式過載 -
-module(helloworld). -export([addnum/2,addnum/3,start/0]). addnum(X,Y) -> Z = X+Y, io:fwrite("~w~n",[Z]). addnum(X,Y,Z) -> A = X+Y+Z, io:fwrite("~w~n",[A]). start() -> addnum(5,5), addnum(5,2,8).
它將產生以下輸出:
10 15
函式重寫
當基類和派生類具有完全相同名稱、相同返回型別和相同引數列表的成員函式時,我們就說它是函式重寫。
使用 C++ 的函式重寫
以下示例演示瞭如何在 C++(一種面向物件程式語言)中進行函式重寫 -
#include <iostream> using namespace std; class A { public: void display() { cout<<"Base class"; } }; class B:public A { public: void display() { cout<<"Derived Class"; } }; int main() { B obj; obj.display(); return 0; }
它將產生以下輸出
Derived Class
使用 Python 的函式重寫
以下示例演示瞭如何在 Python(一種函數語言程式設計語言)中執行函式重寫 -
class A(object): def disp(self): print "Base Class" class B(A): def disp(self): print "Derived Class" x = A() y = B() x.disp() y.disp()
它將產生以下輸出:
Base Class Derived Class
函數語言程式設計 - 遞迴
一個呼叫自身的函式稱為遞迴函式,這種技術稱為遞迴。遞迴指令會持續執行,直到另一個指令阻止它。
C++ 中的遞迴
以下示例演示了遞迴如何在 C++(一種面向物件程式語言)中工作 -
#include <stdio.h> long int fact(int n); int main() { int n; printf("Enter a positive integer: "); scanf("%d", &n); printf("Factorial of %d = %ld", n, fact(n)); return 0; } long int fact(int n) { if (n >= 1) return n*fact(n-1); else return 1; }
它將產生以下輸出
Enter a positive integer: 5 Factorial of 5 = 120
Python 中的遞迴
以下示例演示了遞迴如何在 Python(一種函數語言程式設計語言)中工作 -
def fact(n): if n == 1: return n else: return n* fact (n-1) # accepts input from user num = int(input("Enter a number: ")) # check whether number is positive or not if num < 0: print("Sorry, factorial does not exist for negative numbers") else: print("The factorial of " + str(num) + " is " + str(fact(num)))
它將產生以下輸出:
Enter a number: 6 The factorial of 6 is 720
高階函式
高階函式 (HOF) 是至少滿足以下條件之一的函式 -
- 將一個或多個函式作為引數
- 返回一個函式作為其結果
PHP 中的 HOF
以下示例演示瞭如何在 PHP(一種面向物件程式語言)中編寫高階函式 -
<?php $twice = function($f, $v) { return $f($f($v)); }; $f = function($v) { return $v + 3; }; echo($twice($f, 7));
它將產生以下輸出:
13
Python 中的 HOF
以下示例演示瞭如何在 Python(一種面向物件程式語言)中編寫高階函式 -
def twice(function): return lambda x: function(function(x)) def f(x): return x + 3 g = twice(f) print g(7)
它將產生以下輸出:
13
函數語言程式設計 - 資料型別
資料型別定義了物件可以具有的值型別以及可以在其上執行的操作。在使用資料型別之前,應首先宣告它。不同的程式語言支援不同的資料型別。例如,
- C 支援 char、int、float、long 等。
- Python 支援字串、列表、元組等。
從廣義上講,資料型別有三種 -
基本資料型別 - 這些是程式設計師直接使用的預定義資料型別,用於根據需要僅儲存一個值,即整數型別、字元型別或浮點型別。例如 - int、char、float 等。
派生資料型別 - 這些資料型別是使用內建資料型別派生的,由程式設計師設計用於根據其需要儲存相同型別多個值。例如 - 陣列、指標、函式、列表等。
使用者定義資料型別 - 這些資料型別是使用內建資料型別派生的,這些資料型別被封裝到單個數據型別中,用於根據需要儲存相同型別或不同型別或同時儲存兩種型別的多個值。例如 - 類、結構體等。
C++ 支援的資料型別
下表列出了 C++ 支援的資料型別 -
資料型別 | 大小 | 範圍 |
---|---|---|
char | 1 位元組 | -128 到 127 或 0 到 255 |
unsigned char | 1 位元組 | 0 到 255 |
signed char | 1 位元組 | -128 到 127 |
int | 4 位元組 | -2147483648 到 2147483647 |
unsigned int | 4 位元組 | 0 到 4294967295 |
signed int | 4 位元組 | -2147483648 到 2147483647 |
short int | 2 位元組 | -32768 到 32767 |
unsigned short int | 2 位元組 | 0 到 65,535 |
signed short int | 2 位元組 | -32768 到 32767 |
long int | 4 位元組 | -2,147,483,648 到 2,147,483,647 |
signed long int | 4 位元組 | -2,147,483,648 到 2,147,483,647 |
unsigned long int | 4 位元組 | 0 到 4,294,967,295 |
float | 4 位元組 | +/- 3.4e +/- 38 (~7 位) |
double | 8 位元組 | +/- 1.7e +/- 308 (~15 位) |
long double | 8 位元組 | +/- 1.7e +/- 308 (~15 位) |
Java 支援的資料型別
Java 支援以下資料型別 -
資料型別 | 大小 | 範圍 |
---|---|---|
byte | 1 位元組 | -128 到 127 |
char | 2 位元組 | 0 到 65,536 |
short | 2 位元組 | -32,7688 到 32,767 |
int | 4 位元組 | -2,147,483,648 到 2,147,483,647 |
long | 8 位元組 | -9,223,372,036,854,775,808 到 9,223,372,036,854,775,807 |
float | 4 位元組 | -2147483648 到 2147483647 |
double | 8 位元組 | +9.223*1018 |
Boolean | 1 位 | True 或 False |
Erlang 支援的資料型別
在本節中,我們將討論 Erlang(一種函數語言程式設計語言)支援的資料型別。
數字
Erlang 支援兩種型別的數字字面量,即整數和浮點數。請檢視以下示例,該示例演示瞭如何新增兩個整數值 -
-module(helloworld). -export([start/0]). start() -> io:fwrite("~w",[5+4]).
它將產生以下輸出 -
9
原子
原子是一個其值不能更改的字串。它必須以小寫字母開頭,並且可以包含任何字母數字字元和特殊字元。當原子包含特殊字元時,應將其括在單引號 (') 內。請檢視以下示例以更好地理解。
-module(helloworld). -export([start/0]). start()-> io:fwrite(monday).
它將產生以下輸出:
monday
注意 - 嘗試將原子更改為以大寫“M”開頭的“Monday”。程式將產生錯誤。
Boolean
此資料型別用於將結果顯示為true或false。請檢視以下示例。它演示瞭如何比較兩個整數。
-module(helloworld). -export([start/0]). start() -> io:fwrite(5 =< 9).
它將產生以下輸出:
true
位字串
位字串用於儲存未型別化記憶體區域。請檢視以下示例。它演示瞭如何將位字串的 2 位轉換為列表。
-module(helloworld). -export([start/0]). start() -> Bin2 = <<15,25>>, P = binary_to_list(Bin2), io:fwrite("~w",[P]).
它將產生以下輸出:
[15,25]
元組
元組是一種複合資料型別,具有固定數量的項。元組的每一項都稱為元素。元素的數量是元組的大小。以下示例演示瞭如何定義一個包含 5 項的元組並列印其大小。
-module(helloworld). -export([start/0]). start() -> K = {abc,50,pqr,60,{xyz,75}} , io:fwrite("~w",[tuple_size(K)]).
它將產生以下輸出:
5
對映
對映是一種複合資料型別,具有可變數量的鍵值關聯。對映中的每個鍵值關聯都稱為關聯對。對的鍵和值部分稱為元素。關聯對的數量稱為對映的大小。以下示例演示瞭如何定義一個包含 3 個對映的對映並列印其大小。
-module(helloworld). -export([start/0]). start() -> Map1 = #{name => 'abc',age => 40, gender => 'M'}, io:fwrite("~w",[map_size(Map1)]).
它將產生以下輸出:
3
列表
列表是一種複合資料型別,具有可變數量的項。列表中的每一項都稱為元素。元素的數量稱為列表的長度。以下示例演示瞭如何定義一個包含 5 個專案的列表並列印其大小。
-module(helloworld). -export([start/0]). start() -> List1 = [10,15,20,25,30] , io:fwrite("~w",[length(List1)]).
它將產生以下輸出:
5
注意 - Erlang 中未定義“字串”資料型別。
函數語言程式設計 - 多型性
在程式設計方面,多型性意味著多次重用單個程式碼。更具體地說,它是一種程式能夠根據其資料型別或類以不同方式處理物件的能力。
多型性分為兩種 -
編譯時多型性 - 此型別的多型性可以透過方法過載來實現。
執行時多型性 - 此型別的多型性可以透過方法重寫和虛擬函式來實現。
多型性的優點
多型性提供以下優點 -
它幫助程式設計師重用程式碼,即,一旦編寫、測試和實現的類可以根據需要重用。節省大量時間。
單個變數可用於儲存多種資料型別。
易於除錯程式碼。
多型資料型別
可以使用泛型指標實現多型資料型別,泛型指標僅儲存位元組地址,而不儲存該記憶體地址處儲存的資料型別。例如,
function1(void *p, void *q)
其中p和q是泛型指標,可以將int、float(或任何其他)值作為引數。
C++ 中的多型函式
以下程式演示瞭如何在 C++(一種面向物件程式語言)中使用多型函式。
#include <iostream> Using namespace std: class A { public: void show() { cout << "A class method is called/n"; } }; class B:public A { public: void show() { cout << "B class method is called/n"; } }; int main() { A x; // Base class object B y; // Derived class object x.show(); // A class method is called y.show(); // B class method is called return 0; }
它將產生以下輸出:
A class method is called B class method is called
Python 中的多型函式
以下程式演示瞭如何在 Python(一種函數語言程式設計語言)中使用多型函式。
class A(object): def show(self): print "A class method is called" class B(A): def show(self): print "B class method is called" def checkmethod(clasmethod): clasmethod.show() AObj = A() BObj = B() checkmethod(AObj) checkmethod(BObj)
它將產生以下輸出:
A class method is called B class method is called
函數語言程式設計 - 字串
字串是一組字元,包括空格。我們可以說它是一個字元的一維陣列,以 NULL 字元('\0')結尾。字串也可以被視為大多數程式語言(如 C、C++、Java、PHP、Erlang、Haskell、Lisp 等)支援的預定義類。
下圖顯示了字串“Tutorial”在記憶體中的外觀。

在 C++ 中建立字串
以下程式是一個示例,演示瞭如何在 C++(一種面向物件程式語言)中建立字串。
#include <iostream> using namespace std; int main () { char greeting[20] = {'H', 'o', 'l', 'i', 'd', 'a', 'y', '\0'}; cout << "Today is: "; cout << greeting << endl; return 0; }
它將產生以下輸出:
Today is: Holiday
Erlang 中的字串
以下程式是一個示例,演示瞭如何在 Erlang(一種函數語言程式設計語言)中建立字串。
-module(helloworld). -export([start/0]). start() -> Str = "Today is: Holiday", io:fwrite("~p~n",[Str]).
它將產生以下輸出:
"Today is: Holiday"
C++ 中的字串操作
不同的程式語言支援字串的不同方法。下表顯示了 C++ 支援的一些預定義字串方法。
序號 | 方法和描述 |
---|---|
1 | Strcpy(s1,s2) 它將字串 s2 複製到字串 s1 中 |
2 | Strcat(s1,s2) 它將字串 s2 新增到 s1 的末尾 |
3 | Strlen(s1) 它提供字串 s1 的長度 |
4 | Strcmp(s1,s2) 當字串 s1 和 s2 相同時,它返回 0 |
5 | Strchr(s1,ch) 它返回指向字串 s1 中字元 ch 首次出現的指標 |
6 | Strstr(s1,s2) 它返回字串 s1 中字串 s2 的第一次出現的指標。 |
以下程式展示瞭如何在 C++ 中使用上述方法 -
#include <iostream> #include <cstring> using namespace std; int main () { char str1[20] = "Today is "; char str2[20] = "Monday"; char str3[20]; int len ; strcpy( str3, str1); // copy str1 into str3 cout << "strcpy( str3, str1) : " << str3 << endl; strcat( str1, str2); // concatenates str1 and str2 cout << "strcat( str1, str2): " << str1 << endl; len = strlen(str1); // String length after concatenation cout << "strlen(str1) : " << len << endl; return 0; }
它將產生以下輸出:
strcpy(str3, str1) : Today is strcat(str1, str2) : Today is Monday strlen(str1) : 15
Erlang 中的字串操作
下表顯示了 Erlang 支援的預定義字串方法列表。
序號 | 方法和描述 |
---|---|
1 | len(s1) 返回給定字串中的字元數。 |
2 | equal(s1,s2) 當字串 s1 和 s2 相等時返回 true,否則返回 false。 |
3 | concat(s1,s2) 它將字串 s2 新增到字串 s1 的末尾。 |
4 | str(s1,ch) 它返回字元 ch 在字串 s1 中的索引位置。 |
5 | str (s1,s2) 它返回 s2 在字串 s1 中的索引位置。 |
6 | substr(s1,s2,num) 此方法根據起始位置和從起始位置開始的字元數,從字串 s1 中返回字串 s2。 |
7 | to_lower(s1) 此方法返回小寫字串。 |
以下程式展示瞭如何在 Erlang 中使用上述方法。
-module(helloworld). -import(string,[concat/2]). -export([start/0]). start() -> S1 = "Today is ", S2 = "Monday", S3 = concat(S1,S2), io:fwrite("~p~n",[S3]).
它將產生以下輸出:
"Today is Monday"
函數語言程式設計 - 列表
列表是函數語言程式設計語言中最通用的資料型別,用於儲存一系列相似的資料項。這個概念類似於面向物件程式設計中的陣列。列表項可以寫在方括號中,用逗號分隔。將資料寫入列表的方式因語言而異。
在 Java 中建立數字列表的程式
列表不是 Java/C/C++ 中的資料型別,但我們有替代方法在 Java 中建立列表,即使用ArrayList和LinkedList。
以下示例展示瞭如何在 Java 中建立列表。這裡我們使用 LinkedList 方法來建立數字列表。
import java.util.*; import java.lang.*; import java.io.*; /* Name of the class has to be "Main" only if the class is public. */ public class HelloWorld { public static void main (String[] args) throws java.lang.Exception { List<String> listStrings = new LinkedList<String>(); listStrings.add("1"); listStrings.add("2"); listStrings.add("3"); listStrings.add("4"); listStrings.add("5"); System.out.println(listStrings); } }
它將產生以下輸出:
[1, 2, 3, 4, 5]
在 Erlang 中建立數字列表的程式
-module(helloworld). -export([start/0]). start() -> Lst = [1,2,3,4,5], io:fwrite("~w~n",[Lst]).
它將產生以下輸出:
[1 2 3 4 5]
Java 中的列表操作
在本節中,我們將討論一些可以在 Java 中對列表執行的操作。
向列表中新增元素
方法 add(Object)、add(index, Object)、addAll() 用於向列表中新增元素。例如,
ListStrings.add(3, “three”)
從列表中刪除元素
方法 remove(index) 或 removeobject() 用於從列表中刪除元素。例如,
ListStrings.remove(3,”three”)
注意 - 要刪除列表中的所有元素,請使用 clear() 方法。
從列表中檢索元素
get() 方法用於從指定位置的列表中檢索元素。getFirst() 和 getLast() 方法可以在 LinkedList 類中使用。例如,
String str = ListStrings.get(2)
更新列表中的元素
set(index,element) 方法用於使用指定元素更新指定索引處的元素。例如,
listStrings.set(2,”to”)
對列表中的元素進行排序
方法 collection.sort() 和 collection.reverse() 用於按升序或降序對列表進行排序。例如,
Collection.sort(listStrings)
在列表中搜索元素
以下三種方法根據需要使用 -
布林型 contains(Object) 方法如果列表包含指定的元素則返回true,否則返回false。
int indexOf(Object) 方法返回列表中指定元素第一次出現的索引,如果找不到該元素則返回 -1。
int lastIndexOf(Object) 返回列表中指定元素最後一次出現的索引,如果找不到該元素則返回 -1。
Erlang 中的列表操作
在本節中,我們將討論一些可以在 Erlang 中對列表執行的操作。
新增兩個列表
append(listfirst, listsecond) 方法用於透過新增兩個列表來建立一個新列表。例如,
append(list1,list2)
刪除元素
delete(element, listname) 方法用於從列表中刪除指定的元素,並返回新列表。例如,
delete(5,list1)
從列表中刪除最後一個元素
droplast(listname) 方法用於從列表中刪除最後一個元素並返回一個新列表。例如,
droplast(list1)
搜尋元素
member(element, listname) 方法用於在列表中搜索元素,如果找到則返回 true,否則返回 false。例如,
member(5,list1)
獲取最大值和最小值
max(listname) 和 min(listname) 方法用於查詢列表中的最大值和最小值。例如,
max(list1)
對列表元素進行排序
方法 sort(listname) 和 reverse(listname) 用於按升序或降序對列表進行排序。例如,
sort(list1)
新增列表元素
sum(listname) 方法用於將列表的所有元素加起來並返回它們的和。例如,
sum(list1)
使用 Java 按升序和降序對列表進行排序
以下程式展示瞭如何使用 Java 按升序和降序對列表進行排序 -
import java.util.*; import java.lang.*; import java.io.*; public class SortList { public static void main (String[] args) throws java.lang.Exception { List<String> list1 = new ArrayList<String>(); list1.add("5"); list1.add("3"); list1.add("1"); list1.add("4"); list1.add("2"); System.out.println("list before sorting: " + list1); Collections.sort(list1); System.out.println("list in ascending order: " + list1); Collections.reverse(list1); System.out.println("list in dsending order: " + list1); } }
它將產生以下輸出:
list before sorting : [5, 3, 1, 4, 2] list in ascending order : [1, 2, 3, 4, 5] list in dsending order : [5, 4, 3, 2, 1]
使用 Erlang 按升序對列表進行排序
以下程式展示瞭如何使用 Erlang(一種函數語言程式設計語言)按升序和降序對列表進行排序 -
-module(helloworld). -import(lists,[sort/1]). -export([start/0]). start() -> List1 = [5,3,4,2,1], io:fwrite("~p~n",[sort(List1)]),
它將產生以下輸出:
[1,2,3,4,5]
函數語言程式設計 - 元組
元組是一種複合資料型別,具有固定數量的項。元組中的每個項稱為元素。元素的數量是元組的大小。
在 C# 中定義元組的程式
以下程式展示瞭如何使用 C#(一種面向物件程式語言)定義一個包含四個項的元組並列印它們。
using System; public class Test { public static void Main() { var t1 = Tuple.Create(1, 2, 3, new Tuple<int, int>(4, 5)); Console.WriteLine("Tuple:" + t1); } }
它將產生以下輸出:
Tuple :(1, 2, 3, (4, 5))
在 Erlang 中定義元組的程式
以下程式展示瞭如何使用 Erlang(一種函數語言程式設計語言)定義一個包含四個項的元組並列印它們。
-module(helloworld). -export([start/0]). start() -> P = {1,2,3,{4,5}} , io:fwrite("~w",[P]).
它將產生以下輸出:
{1, 2, 3, {4, 5}}
元組的優點
元組提供以下優點 -
元組本質上是固定大小的,即我們不能向元組新增/刪除元素。
我們可以在元組中搜索任何元素。
元組比列表快,因為它們具有恆定的值集。
元組可以用作字典鍵,因為它們包含不可變的值,如字串、數字等。
元組與列表
元組 | 列表 |
---|---|
元組是不可變的,即我們不能更新其資料。 | 列表是可變的,即我們可以更新其資料。 |
元組中的元素可以是不同型別。 | 列表中的所有元素都是同一型別。 |
元組用圓括號表示元素。 | 列表用方括號表示元素。 |
元組上的操作
在本節中,我們將討論一些可以在元組上執行的操作。
檢查插入的值是否為元組
方法is_tuple(tuplevalues)用於確定插入的值是否為元組。當插入的值為元組時,它返回true,否則返回false。例如,
-module(helloworld). -export([start/0]). start() -> K = {abc,50,pqr,60,{xyz,75}} , io:fwrite("~w",[is_tuple(K)]).
它將產生以下輸出:
True
將列表轉換為元組
方法list_to_tuple(listvalues)將列表轉換為元組。例如,
-module(helloworld). -export([start/0]). start() -> io:fwrite("~w",[list_to_tuple([1,2,3,4,5])]).
它將產生以下輸出:
{1, 2, 3, 4, 5}
將元組轉換為列表
方法tuple_to_list(tuplevalues)將指定的元組轉換為列表格式。例如,
-module(helloworld). -export([start/0]). start() -> io:fwrite("~w",[tuple_to_list({1,2,3,4,5})]).
它將產生以下輸出:
[1, 2, 3, 4, 5]
檢查元組大小
方法tuple_size(tuplename)返回元組的大小。例如,
-module(helloworld). -export([start/0]). start() -> K = {abc,50,pqr,60,{xyz,75}} , io:fwrite("~w",[tuple_size(K)]).
它將產生以下輸出:
5
函數語言程式設計 - 記錄
記錄是一種用於儲存固定數量元素的資料結構。它類似於 C 語言中的結構體。在編譯時,其表示式會被翻譯成元組表示式。
如何建立記錄?
關鍵字“record”用於建立記錄,並指定記錄名稱及其欄位。其語法如下 -
record(recodname, {field1, field2, . . fieldn})
將值插入記錄的語法為 -
#recordname {fieldName1 = value1, fieldName2 = value2 .. fieldNamen = valuen}
使用 Erlang 建立記錄的程式
在以下示例中,我們建立了一個名為student的記錄,它有兩個欄位,即sname和sid。
-module(helloworld). -export([start/0]). -record(student, {sname = "", sid}). start() -> S = #student{sname = "Sachin",sid = 5}.
使用 C++ 建立記錄的程式
以下示例展示瞭如何使用 C++(一種面向物件程式語言)建立記錄 -
#include<iostream> #include<string> using namespace std; class student { public: string sname; int sid; 15 }; int main() { student S; S.sname = "Sachin"; S.sid = 5; return 0; }
使用 Erlang 訪問記錄值的程式
以下程式展示瞭如何使用 Erlang(一種函數語言程式設計語言)訪問記錄值 -
-module(helloworld). -export([start/0]). -record(student, {sname = "", sid}). start() -> S = #student{sname = "Sachin",sid = 5}, io:fwrite("~p~n",[S#student.sid]), io:fwrite("~p~n",[S#student.sname]).
它將產生以下輸出:
5 "Sachin"
使用 C++ 訪問記錄值的程式
以下程式展示瞭如何使用 C++ 訪問記錄值 -
#include<iostream> #include<string> using namespace std; class student { public: string sname; int sid; }; int main() { student S; S.sname = "Sachin"; S.sid = 5; cout<<S.sid<<"\n"<<S.sname; return 0; }
它將產生以下輸出:
5 Sachin
可以透過將值更改為特定欄位,然後將該記錄分配給新的變數名來更新記錄值。請檢視以下兩個示例,瞭解如何在面向物件和函數語言程式設計語言中完成此操作。
使用 Erlang 更新記錄值的程式
以下程式展示瞭如何使用 Erlang 更新記錄值 -
-module(helloworld). -export([start/0]). -record(student, {sname = "", sid}). start() -> S = #student{sname = "Sachin",sid = 5}, S1 = S#student{sname = "Jonny"}, io:fwrite("~p~n",[S1#student.sid]), io:fwrite("~p~n",[S1#student.sname]).
它將產生以下輸出:
5 "Jonny"
使用 C++ 更新記錄值的程式
以下程式展示瞭如何使用 C++ 更新記錄值 -
#include<iostream> #include<string> using namespace std; class student { public: string sname; int sid; }; int main() { student S; S.sname = "Jonny"; S.sid = 5; cout<<S.sname<<"\n"<<S.sid; cout<<"\n"<< "value after updating"<<"\n"; S.sid = 10; cout<<S.sname<<"\n"<<S.sid; return 0; }
它將產生以下輸出:
Jonny 5 value after updating Jonny 10
函數語言程式設計 - Lambda 演算
Lambda 演算是一個由 Alonzo Church 在 1930 年代開發的框架,用於研究使用函式進行計算。
函式建立 - Church 引入了λx.E符號來表示函式,其中“x”是形式引數,“E”是函式體。這些函式可以是無名函式和單引數函式。
函式應用 - Church 使用E1.E2符號來表示將函式E1應用於實際引數E2。並且所有函式都是單引數函式。
Lambda 演算的語法
Lambda 演算包括三種不同型別的表示式,即:
E :: = x(變數)
| E1 E2(函式應用)
| λx.E(函式建立)
其中λx.E稱為 Lambda 抽象,E 稱為 λ-表示式。
評估 Lambda 演算
純 Lambda 演算沒有內建函式。讓我們評估以下表達式 -
(+ (* 5 6) (* 8 3))
在這裡,我們不能以“+”開頭,因為它只對數字進行運算。有兩個可約表示式:(* 5 6) 和 (* 8 3)。
我們可以先減少其中一個。例如 -
(+ (* 5 6) (* 8 3)) (+ 30 (* 8 3)) (+ 30 24) = 54
β-歸約規則
我們需要一個歸約規則來處理 λs。
(λx . * 2 x) 4 (* 2 4) = 8
這稱為 β-歸約。
形式引數可以使用多次 -
(λx . + x x) 4 (+ 4 4) = 8
當有多個項時,我們可以按如下方式處理它們 -
(λx . (λx . + (− x 1)) x 3) 9
內部x屬於內部λ,外部 x 屬於外部λ。
(λx . + (− x 1)) 9 3 + (− 9 1) 3 + 8 3 = 11
自由變數和繫結變數
在一個表示式中,變數的每次出現要麼是“自由的”(對 λ),要麼是“繫結的”(對 λ)。
(λx . E) y 的 β-歸約將E中每個自由出現的x替換為y。例如 -

Alpha 歸約
Alpha 歸約非常簡單,可以在不改變 lambda 表示式含義的情況下完成。
λx . (λx . x) (+ 1 x) ↔ α λx . (λy . y) (+ 1 x)
例如 -
(λx . (λx . + (− x 1)) x 3) 9 (λx . (λy . + (− y 1)) x 3) 9 (λy . + (− y 1)) 9 3 + (− 9 1) 3 + 8 3 11
Church-Rosser 定理
Church-Rosser 定理陳述如下 -
如果 E1 ↔ E2,則存在一個 E 使得 E1 → E 且 E2 → E。“以任何方式進行歸約最終都可以產生相同的結果。”
如果 E1 → E2,且 E2 是正規化,則 E1 到 E2 的正則順序歸約存在。“如果存在正規化,則正則順序歸約將始終產生正規化。”
函數語言程式設計 - 惰性求值
惰性求值(Lazy evaluation)是一種求值策略,它延遲表示式求值,直到需要其值時才進行計算。它避免了重複計算。Haskell就是一個很好的例子,這門函數語言程式設計語言的基礎就是建立在惰性求值之上的。
惰性求值被用於Unix的map函式,透過只加載磁碟上需要的頁面來提高效能。剩餘的頁面不會分配記憶體。
惰性求值 - 優點
它允許語言執行時丟棄與表示式最終結果沒有直接關聯的子表示式。
它透過丟棄臨時計算和條件判斷來減少演算法的時間複雜度。
它允許程式設計師在初始化資料結構的元件後以任意順序訪問它們,只要它們沒有迴圈依賴關係。
它最適合載入那些很少訪問的資料。
惰性求值 - 缺點
它迫使語言執行時透過建立thunk(延遲物件)來儲存子表示式的求值,直到最終結果需要它。
有時它會增加演算法的空間複雜度。
很難確定它的效能,因為它包含了在執行之前表示式的thunk。
使用Python實現惰性求值
Python中的range方法遵循惰性求值的理念。它節省了較大範圍的執行時間,並且我們不需要一次獲取所有值,因此也節省了記憶體消耗。請看下面的例子。
r = range(10) print(r) range(0, 10) print(r[3])
它將產生以下輸出:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 3
檔案I/O操作
當程式終止時,我們需要檔案來儲存程式的輸出。使用檔案,我們可以使用不同語言中的各種命令訪問相關資訊。
以下是可以在檔案上執行的一些操作列表:
- 建立新檔案
- 開啟現有檔案
- 讀取檔案內容
- 在檔案中搜索資料
- 寫入新檔案
- 更新現有檔案的內容
- 刪除檔案
- 關閉檔案
寫入檔案
要將內容寫入檔案,首先需要開啟所需的檔案。如果指定的檔案不存在,則會建立一個新檔案。
讓我們看看如何使用C++將內容寫入檔案。
示例
#include <iostream> #include <fstream> using namespace std; int main () { ofstream myfile; myfile.open ("Tempfile.txt", ios::out); myfile << "Writing Contents to file.\n"; cout << "Data inserted into file"; myfile.close(); return 0; }
注意 -
fstream是用於控制檔案讀寫操作的流類。
ofstream是用於將內容寫入檔案的流類。
讓我們看看如何使用Erlang(一種函數語言程式設計語言)將內容寫入檔案。
-module(helloworld). -export([start/0]). start() -> {ok, File1} = file:open("Tempfile.txt", [write]), file:write(File1,"Writting contents to file"), io:fwrite("Data inserted into file\n").
注意 -
要開啟檔案,我們必須使用open(filename,mode)。
寫入檔案內容的語法:write(filemode,file_content)。
輸出 - 當我們執行這段程式碼時,“Writing contents to file”將被寫入檔案Tempfile.txt中。如果檔案有任何現有內容,則將被覆蓋。
從檔案讀取
要從檔案讀取,首先必須以讀取模式開啟指定的檔案。如果檔案不存在,則其相應的方法返回NULL。
以下程式演示瞭如何在C++中讀取檔案內容:
#include <iostream> #include <fstream> #include <string> using namespace std; int main () { string readfile; ifstream myfile ("Tempfile.txt",ios::in); if (myfile.is_open()) { while ( getline (myfile,readfile) ) { cout << readfile << '\n'; } myfile.close(); } else cout << "file doesn't exist"; return 0; }
它將產生以下輸出:
Writing contents to file
注意 - 在此程式中,我們使用“ios::in”以讀取模式打開了一個文字檔案,然後將其內容列印到螢幕上。我們使用了while迴圈,使用“getline”方法逐行讀取檔案內容。
以下程式演示瞭如何使用Erlang執行相同的操作。在這裡,我們將使用read_file(filename)方法讀取指定檔案中的所有內容。
-module(helloworld). -export([start/0]). start() -> rdfile = file:read_file("Tempfile.txt"), io:fwrite("~p~n",[rdfile]).
它將產生以下輸出:
ok, Writing contents to file
刪除現有檔案
我們可以使用檔案操作刪除現有檔案。以下程式演示瞭如何使用C++刪除現有檔案:
#include <stdio.h> int main () { if(remove( "Tempfile.txt" ) != 0 ) perror( "File doesn’t exist, can’t delete" ); else puts( "file deleted successfully " ); return 0; }
它將產生以下輸出:
file deleted successfully
以下程式演示瞭如何在Erlang中執行相同的操作。在這裡,我們將使用delete(filename)方法刪除現有檔案。
-module(helloworld). -export([start/0]). start() -> file:delete("Tempfile.txt").
輸出 - 如果檔案“Tempfile.txt”存在,則將其刪除。
確定檔案大小
以下程式演示瞭如何使用C++確定檔案的大小。這裡,函式fseek將與流關聯的位置指示器設定為新位置,而ftell返回流中的當前位置。
#include <stdio.h> int main () { FILE * checkfile; long size; checkfile = fopen ("Tempfile.txt","rb"); if (checkfile == NULL) perror ("file can’t open"); else { fseek (checkfile, 0, SEEK_END); // non-portable size = ftell (checkfile); fclose (checkfile); printf ("Size of Tempfile.txt: %ld bytes.\n",size); } return 0; }
輸出 - 如果檔案“Tempfile.txt”存在,則將顯示其大小(以位元組為單位)。
以下程式演示瞭如何在Erlang中執行相同的操作。在這裡,我們將使用file_size(filename)方法確定檔案的大小。
-module(helloworld). -export([start/0]). start() -> io:fwrite("~w~n",[filelib:file_size("Tempfile.txt")]).
輸出 - 如果檔案“Tempfile.txt”存在,則將顯示其大小(以位元組為單位)。否則,將顯示“0”。