2011-09-28 11 views
8

Để phân công bài tập về nhà, chúng tôi đã được hướng dẫn hoàn thành một nhiệm vụ mà không giới thiệu bất kỳ "tác dụng phụ" nào. Tôi đã tra cứu "tác dụng phụ" trên Wikipedia, và mặc dù tôi hiểu rằng theo lý thuyết nó có nghĩa là "sửa đổi trạng thái hoặc có tương tác quan sát được với chức năng gọi", tôi đang gặp khó khăn trong việc tìm ra các chi tiết cụ thể.OCaml: Việc lưu trữ một số giá trị sẽ được sử dụng sau này có giới thiệu "tác dụng phụ" không?

Ví dụ: việc tạo một giá trị chứa kết quả thời gian không biên dịch có giới thiệu các tác dụng phụ không?

Nói rằng tôi đã có (có thể không được hoàn hảo cú pháp):

val myList = (someFunction x y);; 
if List.exists ((=) 7) myList then true else false;; 

này sẽ giới thiệu tác dụng phụ? Tôi đoán có lẽ tôi đang bối rối về những gì "sửa đổi một nhà nước" có nghĩa là trong định nghĩa của tác dụng phụ.

+3

Một gợi ý cho kiểu: Mẫu "nếu biểu thức sau đó đúng sai" hoặc các mẫu tương tự khác rất phổ biến trong số những người mới bắt đầu. Nếu bạn nghĩ về nó, cho phần nếu được chọn thì biểu thức phải đúng và đối với phần khác thì nó phải là sai. Vì vậy, mô hình này có thể được giảm xuống và giảm xuống để "biểu hiện". – LiKao

+0

Bạn có thể hiển thị mã cho điều đó không? Tôi chắc chắn là một người mới bắt đầu và có thể sử dụng một số hướng dẫn. –

+0

Chắc chắn, nó khá đơn giản: Thay vì "nếu List.exists ((=) 7) myList thì đúng là false ;;" bạn chỉ có thể viết "List.exists ((=) 7) myList ;;". Nếu bạn dừng lại để suy nghĩ về những lý do, tại sao hai phát biểu này có cùng ngữ nghĩa, bạn sẽ học được rất nhiều về lập trình hàm (và cũng chung). – LiKao

Trả lời

8

Không; một tác dụng phụ đề cập đến ví dụ: biến đổi ô ref với toán tử gán := hoặc các thứ khác có giá trị được gọi bằng tên thay đổi theo thời gian. Trong trường hợp này, myList là một giá trị bất biến không bao giờ thay đổi trong suốt chương trình, do đó nó không có hiệu lực.

Xem thêm

http://en.wikipedia.org/wiki/Referential_transparency_(computer_science)

+0

Cảm ơn, liên kết đó rất hữu ích để hiểu rõ hơn về lập trình chức năng và các tác dụng phụ. –

5

Một cách tốt để suy nghĩ về nó là "có tôi đã thay đổi bất cứ điều gì mà bất kỳ mã sau (bao gồm cả chạy chức năng này tương tự lại sau) bao giờ có thể có thể nhìn thấy khác với giá trị tôi đang trở về? " Nếu vậy, đó là một tác dụng phụ. Nếu không, sau đó bạn có thể biết rằng không có một.

Vì vậy, một cái gì đó như:

let inc_nosf v = v+1 

không có tác dụng phụ bởi vì nó chỉ trả về một giá trị mới đó là một trong hơn một số nguyên v Vì vậy, nếu bạn chạy đoạn mã sau trong mục cấp đầu ocaml, bạn nhận được. các kết quả tương ứng:

# let x = 5;; 
val x : int = 5 
# inc_nosf x;; 
- : int = 6 
# x;; 
- : int = 5 

Như bạn có thể thấy, giá trị của x không thay đổi. Vì vậy, vì chúng tôi không lưu giá trị trả lại, sau đó không có gì thực sự tăng lên. Hàm của chúng ta chỉ thay đổi giá trị trả về, chứ không phải x. Vì vậy, để lưu nó vào x, chúng ta sẽ phải làm:

# let x = inc_nosf x;; 
val x : int = 6 
# x;; 
- : int = 6 

Kể từ khi chức năng inc_nosf không có tác dụng phụ (có nghĩa là, nó chỉ giao tiếp với thế giới bên ngoài sử dụng giá trị trả về của nó, chứ không phải bằng cách làm cho bất kỳ khác thay đổi).

Nhưng cái gì đó như:

let inc_sf r = r := !r+1 

có tác dụng phụ vì nó thay đổi giá trị được lưu trữ trong các tài liệu tham khảo đại diện bởi r. Vì vậy, nếu bạn chạy mã tương tự ở cấp cao nhất, bạn có được điều này, thay vì:

# let y = ref 5;; 
val y : int ref = {contents = 5} 
# inc_sf y;; 
- : unit =() 
# y;; 
- : int ref = {contents = 6} 

Vì vậy, trong trường hợp này, mặc dù chúng tôi vẫn không lưu các giá trị trả về, nó đã tăng lên anyway. Điều đó có nghĩa là phải có những thay đổi đối với một cái gì đó khác với giá trị trả về. Trong trường hợp này, thay đổi đó là nhiệm vụ sử dụng := đã thay đổi giá trị được lưu trữ của ref.

Như một quy tắc hay, trong Ocaml, nếu bạn tránh sử dụng ref, bản ghi, lớp, chuỗi, mảng và bảng băm, thì bạn sẽ tránh được bất kỳ nguy cơ tác dụng phụ nào. Mặc dù bạn có thể sử dụng một cách an toàn các chuỗi ký tự miễn là bạn tránh sửa đổi chuỗi tại chỗ bằng cách sử dụng các hàm như String.set hoặc String.fill. Về cơ bản, bất kỳ chức năng nào có thể sửa đổi một kiểu dữ liệu tại chỗ sẽ gây ra một tác dụng phụ.