Tại sao cú pháp ngôn ngữ chức năng gần với ngôn ngữ của con người hơn?


14

Tôi quan tâm đến lập trình chức năng và quyết định đối đầu với Haskell. Đầu tôi đau ... nhưng cuối cùng tôi cũng sẽ hiểu ... Tôi có một sự tò mò, tại sao cú pháp lại khó hiểu như vậy (thiếu một từ khác)?

Có một lý do tại sao nó không biểu cảm hơn, gần gũi hơn với ngôn ngữ của con người?

Tôi hiểu rằng FP rất giỏi trong việc mô hình hóa các khái niệm toán học và nó đã mượn một số phương tiện biểu đạt ngắn gọn, nhưng vẫn không phải là toán học ... đó là một ngôn ngữ.


4
@ratchet freak: :) vậy có cái nào được thiết kế bởi một anh chàng ghét ký hiệu đánh bóng không?
JohnDoDo

10
@ratchetfreak Theo cách nào thì cú pháp Haskell giống với ký hiệu đánh bóng? Các toán tử Haskell là infix, giống như hầu hết các toán tử của các ngôn ngữ khác (và các lệnh gọi hàm là tiền tố - cũng giống như hầu hết các lệnh gọi hàm khác của các ngôn ngữ khác).
sepp2k

9
Đó là một giả định khá lớn / bước nhảy vọt mà bạn đang thực hiện, rằng "gần với ngôn ngữ của con người" tương đương với "biểu cảm hơn".
Matt Ball

7
Bạn đã từng nghe về Cobol và Fortran chưa?
ott--

7
Vì lý do chính xác tương tự mà các nhà toán học đã thay thế các cụm từ Latin dài bằng các biểu thức đại số. Với một chút luyện tập, một ký hiệu nhỏ gọn hơn sẽ hiệu quả hơn rất nhiều.
kevin cline

Câu trả lời:


14

Các ngôn ngữ chức năng như Haskell và tiền đề Miranda trước đây đã phát triển từ khái niệm toán học của phép tính lambda . Từ trang Wikipedia:

Phép tính Lambda (còn được viết là-compus hay còn gọi là "phép tính lambda") là một hệ thống chính thức trong logic toán học để biểu thị tính toán bằng cách liên kết và thay thế biến.

...

Tính toán Lambda đã đóng một vai trò quan trọng trong sự phát triển của lý thuyết về ngôn ngữ lập trình. Các đối tác nổi bật nhất của phép tính lambda trong khoa học máy tính là các ngôn ngữ lập trình chức năng, về cơ bản thực hiện phép tính (tăng thêm một số hằng và kiểu dữ liệu). Ngoài ngôn ngữ lập trình, phép tính lambda còn có nhiều ứng dụng trong lý thuyết chứng minh. Một ví dụ chính cho điều này là sự tương ứng của Curry Curry Howard, đưa ra sự tương ứng giữa các hệ thống tính toán lambda khác nhau và hệ thống logic chính thức.

Do lịch sử này, các cú pháp của các ngôn ngữ chức năng này (và các yếu tố chức năng của các ngôn ngữ mệnh lệnh hơn) bị ảnh hưởng mạnh mẽ bởi ký hiệu toán học được sử dụng bởi phép tính lambda.

Độ chính xác mà cả ký hiệu toán học và ngôn ngữ máy tính có thể mô tả các yêu cầu và độ chính xác mà máy tính yêu cầu các hướng dẫn của chúng được viết tương quan tốt với nhau. Tuy nhiên, sự thiếu chính xác của ngôn ngữ tự nhiên tạo ra một rào cản lớn đối với việc sử dụng nó cho các máy tính lập trình. Ngay cả các môi trường lập trình ngôn ngữ tự nhiên thành công nhất (như được cho là) như Wolfram Alpha cũng cần trải nghiệm tên miền quan trọng để được sử dụng hiệu quả.


29

Haskell cú pháp gần với ngôn ngữ của con người. Nó được thiết kế đặc biệt giống với ký hiệu toán học, là ngôn ngữ được thiết kế bởi con người (do đó là ngôn ngữ của con người ) để diễn đạt chính xác những khái niệm mà Haskell được xây dựng dựa trên.

Bạn có thể hiển thị một đoạn mã Haskell cho bất kỳ nhà toán học hoặc nhà logic học nào, và anh ta sẽ có thể hiểu được nó, ngay cả khi anh ta chưa bao giờ nghe nói về Haskell và hoàn toàn không biết gì về lập trình, khoa học máy tính hoặc thậm chí cả máy tính.

Mặt khác, bạn có thể hiển thị cho bất kỳ nhà toán học hoặc nhà logic học nào một đoạn mã như thế này:

x = x + 1

và anh ta sẽ hoàn toàn bối rối, nói: "Điều này không có ý nghĩa, không có xcái nào xbằng xvới cộng 1."

Có hay không một số ký hiệu cụ thể là "khó hiểu" hay không, là vấn đề quan điểm và sự quen thuộc.


8
Chỉ có một vấn đề với câu trả lời này: Tôi không phải là nhà toán học.
JohnDoDo

6
@ sepp2k: Tôi không đồng ý. Đối với hầu hết mọi người, trước khi tiếp xúc với các ngôn ngữ lập trình và một số cú pháp Haskell nền tảng toán học cơ bản sẽ dễ hiểu hơn nhiều so với mã thủ tục thông thường với tất cả các tác dụng phụ của nó và các câu lệnh môi trường phức tạp được thực thi. Cú pháp như wherecho phép ngưng tụ ý chính của một hàm trong một dòng.
Benjamin Bannier

17
-1: câu trả lời này có vẻ phần lớn là phạm vi. Tôi khá chắc chắn OP có nghĩa là ngôn ngữ nói.
Steven Evers

6
Trên thực tế, tôi khá chắc chắn rằng điều x = infinityđó thực sự giải quyết được phương trình.
DeadMG

6
Chà, ngôn ngữ lập trình cũng được thiết kế bởi con người .... Do đó theo định nghĩa của bạn, chúng là ngôn ngữ của con người.
marco-fiset

13

Tôi nghĩ một điều có lẽ bạn đang gặp phải là điều mà tôi cũng gặp phải khi học lập trình chức năng, đó là với lập trình chức năng, bạn có thể (và gần như phải) nghĩ / làm việc ở cấp độ cao hơn so với lập trình bắt buộc.

Những gì bạn đang tìm thấy ít biểu cảm hơn, tôi nghĩ thực sự biểu cảm hơn : bạn không cần phải đánh vần từng chi tiết nhỏ và có thể làm nhiều hơn với ít mã hơn trong lập trình chức năng - có nhiều sức mạnh hơn những gì bạn viết.

Ví dụ, tôi có thể viết một cách bắt buộc:

for each (Person person in people)
    print(person.name)

đó là hoàn toàn dễ đọc như tiếng Anh.

Phiên bản Haskell có thể là (và đây không phải là Haskell hợp lệ, nhưng chỉ để so sánh cú pháp):

map (print . name) people

trong đó yêu cầu ít mã hơn và ít chi tiết hơn - tôi không phải chia mọi thứ thành một vòng lặp và biến (s) ( for each (...)) của nó, maphàm này đảm nhiệm việc đó cho tôi.

Làm việc ở cấp độ đó có thể mất một số làm quen. Nếu nó giúp được gì, Haskell có lẽ là thời điểm khó khăn nhất tôi đã học một ngôn ngữ mới kể từ khi tôi bắt đầu lập trình và tôi biết> 10 ngôn ngữ (bao gồm cả Lisp). Nó hoàn toàn đáng để học hỏi.


8

Hiện tại tôi đang hiểu về Scala, vì vậy tôi có thể thông cảm. Ít nhất với Scala tôi có thể trở lại phong cách cấp bách khi mọi thứ trở nên quá khó khăn.

Tôi nghĩ rằng có một số lực lượng đang chơi ở đây:

  • Các nhà thiết kế của các ngôn ngữ chức năng nhất thiết phải có một nền tảng toán học mạnh mẽ, vì vậy họ mượn ký hiệu toán học là điều tự nhiên đối với họ.

  • Khả năng biểu đạt cao hơn (nghĩa là sức mạnh của các tuyên bố, thay vì gần gũi với tiếng Anh) của bất kỳ ngôn ngữ nào có (IMO) một mức giá tương ứng trong độ dốc của đường cong học tập. Tersiness là một chất lượng được đánh giá cao trong Scala, với nhiều thứ là tùy chọn.

  • Các ngôn ngữ chức năng chỉ làm những việc rất khác nhau, vì vậy các hoạt động cơ bản không ánh xạ lên các cấu trúc bắt buộc.


3
Tôi cũng sẽ nói thêm rằng các ngôn ngữ chức năng thường có thể diễn tả các khái niệm bậc cao hơn, những khái niệm này trừu tượng hơn, khó đặt tên một cách có ý nghĩa
jk.

1
@jk, vâng, đồng ý! Đồng thời, đó là lý do tại sao họ có một đường cong học tập dốc cho các lập trình viên với nền tảng bắt buộc và toán học nhỏ (như tôi), và tại sao họ đáng giá.
Richard Đóng

3

Nếu tôi hiểu chính xác nhận xét cuối cùng của bạn, câu hỏi của bạn là tại sao Haskell thường sử dụng các toán tử tượng trưng ở những nơi mà nó cũng có thể sử dụng các từ khóa chữ và số (hoặc tên hàm)?

Về từ khóa, một câu trả lời sẽ là từ khóa ngăn bạn sử dụng một số từ nhất định làm tên biến. Ví dụ, tôi luôn thấy khó chịu khi tôi muốn gọi các biến của mình fromtotrong một ngôn ngữ mà một trong số đó là từ khóa - như trong Python.

Một lý do khác cho các nhà khai thác tượng trưng nói chung là sự đồng nhất. Điều đó không thực sự áp dụng trong các ví dụ cụ thể của bạn về việc hiểu danh sách ( <-không ngắn hơn in), nhưng trong nhiều trường hợp thì không.

Một lý do khác là khả năng đọc. Điều đó có vẻ phản trực giác bởi vì các toán tử tượng trưng thường khó học hơn vì "tên" của chúng không thực sự cho bạn biết bất cứ điều gì chúng làm (trong khi tên của hàm thường sẽ), nhưng một khi bạn biết toán tử đã cho thì làm gì, các biểu thức với toán tử ký hiệu infix thường dễ phân tích cú pháp của con người hơn so với một cuộc gọi có nhiều lệnh gọi tiền tố alpha-số vì các toán tử dễ phân biệt trực quan hơn với các toán hạng theo cách đó. Ví dụ, hầu hết mọi người sẽ đồng ý rằng 2 * 3 + 4nó dễ đọc hơn add (mult 2 3) 4hoặc add(mult(2, 3), 4).


@PeterTaylor Không, chỉ là tôi ngu ngốc ;-) Đã sửa bây giờ.
sepp2k

3

Ngôn ngữ máy tính bắt buộc hầu như không gần gũi với ngôn ngữ tự nhiên hơn là, nói, Haskell là.

Tuy nhiên, một số được thiết kế để gần giống với tiếng Anh hơn: ví dụ như Cobol và Hypercard. Những bài học tôi sẽ rút ra từ những ví dụ này là:

  • sự tương đồng với ngôn ngữ tự nhiên dường như không mang lại sự cải thiện trực tiếp về khả năng sử dụng
  • mô phỏng ngôn ngữ tự nhiên trực tiếp có thể mang lại ngôn ngữ máy tính dài dòng và tối nghĩa

Ngôn ngữ máy tính Perl được báo cáo là được thiết kế với một số khía cạnh tinh tế hơn của ngôn ngữ tự nhiên . Tôi sẽ đánh giá rằng Perl làm tốt hơn Cobol hoặc Hypercard về khả năng sử dụng chung, nhưng mọi người có ý kiến ​​khác nhau về Perl.


3

Tôi nghĩ rằng Haskell giống với ngôn ngữ của con người như người ta có thể có được mà không cần đưa ra một cú pháp điên rồ. Nó thực sự rất dài đối với điều này, ví dụ với wheremệnh đề trì hoãn một định nghĩa và với cú pháp hiểu danh sách, đó chính xác là những gì tôi sẽ viết trên bảng đen. Nó cũng tránh các ký tự bên ngoài như niềng răng và có cách sử dụng thụt đầu dòng tự do. Ví dụ điển hình là quicksort:

qsort [] = []
qsort (p:xs) = qsort lesser ++ [p] ++ qsort greater
               where lesser = [x | x <- xs, x <= p] 
                     greater = [x | x <- xs, x > p]

Phải thừa nhận rằng đây là một ví dụ đơn giản, nhưng tôi không biết bất kỳ ngôn ngữ nào khác có thể đọc được như ngôn ngữ này.

Làm những thứ phức tạp hơn có thể trở nên khó đọc trong Haskell, nhưng điều đó phải làm với hệ thống loại, IO bị ràng buộc và hoàn toàn không phải với cú pháp.

Nếu có bất cứ điều gì, tôi sẽ nói rằng Haskell đã hy sinh tính đơn giản cú pháp để phù hợp với một cú pháp giống với ngôn ngữ của con người. Một ngôn ngữ như lược đồ có một cú pháp rất xa so với những gì con người sẽ viết, nhưng nó thực sự đơn giản để giải thích các quy tắc của nó.


3
Tôi hầu như không gọi đó là con người có thể đọc được. Tôi biết quicksort. Tôi quen thuộc với cách thiết lập nó bằng nhiều ngôn ngữ khác nhau, tôi biết những gì nó phải làm và tôi vẫn không thể tạo ra đầu hoặc đuôi ra khỏi nửa dưới của đoạn mã đó.
Mason Wheeler

Tôi đoán nó thực sự phụ thuộc vào nền tảng của bạn. Điều này đơn giản như đối với tôi ...
Andrea

2
Trong mọi trường hợp, nó được cho là giống với ký hiệu này: purplemath.com/modules/setnotn.htm
Andrea

4
Bạn có chắc là không ++ [p] ++?
Peter Taylor

1
@Mason: Có vẻ như khá rõ ràng đối với tôi và tôi chưa bao giờ viết một dòng Haskell
kevin cline

2

Tôi nghĩ rằng sự khác biệt có liên quan đến cách lập trình chức năng / khai báo đưa ra các tuyên bố về một vấn đề như thể đó là một vấn đề toán học, trong đó lập trình bắt buộc mô tả một quy trình . Trong thế giới kinh doanh, các chương trình máy tính bao bọc hoặc thay thế các quy trình vật lý, vì vậy bạn có thể tìm thấy một ngôn ngữ phản ánh điều này trực quan hơn.

Nó chỉ ra rằng phong cách chức năng cho vay để sử dụng an toàn nhiều bộ xử lý (vì nó giảm thiểu khả năng biến đổi và tác dụng phụ) - điều mà chúng ta sẽ thấy nhiều hơn trong tương lai. Ngoài ra, hầu hết các ngôn ngữ chức năng hiện đại đều có các bộ sưu tập với các trình vòng lặp mà bạn có thể truyền các hàm cho. Các phương thức này có thể phân chia khối lượng công việc của chúng trên nhiều bộ xử lý rất hiệu quả mà bạn không hề biết về nó.


Tôi nghĩ rằng đây là câu trả lời tốt nhất - câu trả lời duy nhất làm rõ sự khác biệt giữa quy trình và tuyên bố.
Milind R
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.