2013-03-27 34 views
8

Tôi đang cố gắng hiểu hàm lambda (tức là chức năng ẩn danh) trong Haskell bằng cách viết một vài hàm đơn giản sử dụng chúng.Lỗi khi khai báo hàm lambda: khai báo một cá thể đầu tiên

Trong ví dụ sau, tôi chỉ đơn giản là cố gắng đưa vào 3 tham số và thêm hai trong ba tham số bằng cách sử dụng hàm ẩn danh và thêm tham số thứ ba sau đó. Tôi gặp lỗi khi nói rằng trước tiên tôi phải khai báo một cá thể.

specialAdd x y z = (\x y -> x + y) + z 

Tôi đánh giá cao bất kỳ lời giải thích về việc tại sao ví dụ của tôi là không làm việc và/hoặc bất kỳ lời giải thích mà có thể giúp tôi hiểu rõ hơn về các hàm lambda.

+2

(\ xy -> x + y) :: Num a => a -> a -> a Bạn cố gắng thêm z vào hàm – Vladimir

Trả lời

16

specialAdd x y z = (\x y -> x + y) + z

Trong ví dụ này, những gì bạn đang cố gắng làm là thêm một chức năng để một con số, mà không phải là đi làm việc. Nhìn vào (\x y -> x + y) + z: nó có dạng a + b. Để biểu thức này hoạt động, phần a và phần b phải là các số cùng loại.

Haskell là một ngôn ngữ không bình thường, vì vậy các thông báo lỗi hiếm khi có dạng "bạn không thể làm điều đó".Vì vậy, những gì đang xảy ra ở đây là Haskell thấy rằng (\x y -> x + y) là một hàm, và vì trong một biểu thức như a + b, b phải cùng loại với a, nó kết luận rằng b cũng phải là một hàm. Haskell cũng cho phép bạn xác định các quy tắc của riêng mình để thêm các loại không có sẵn; do đó, nó không thể cung cấp cho bạn một lỗi nói rằng "bạn không thể thêm hai chức năng", nhưng thay vào đó lỗi là "bạn chưa xác định quy tắc cho phép tôi thêm hai chức năng".

Sau đây sẽ làm những gì bạn muốn:

specialAdd x y z = ((\x y -> x + y) x y) + z 

Ở đây bạn đang áp dụng các chức năng (\x y -> x + y) để lập luận xy, sau đó thêm kết quả để z.

1

Bạn đang cố gắng sử dụng (+) như một cái gì đó như (Num a) => (a -> a -> a) -> a -> ?? không chính xác.

(+) được định nghĩa trong lớp Num và (a -> a -> a) không phải là phiên bản của lớp này.

Chính xác bạn đang cố gắng đạt được điều gì?

10

Một cách hay để thực hành chức năng ẩn danh là sử dụng chúng với chức năng bậc cao gấp hoặc bản đồ.

Sử dụng bản đồ như một điểm nhập cảnh,

định nghĩa cơ bản của bản đồ,

map f [] = [] 
map f (x:xs) = f x : f xs 

xây dựng lên một ví dụ,

>>> let list = [0..4] 
>>> let f x = x + 1 

Áp dụng bản đồ chúng tôi có được,

>>> map f list 
[1,2,3,4,5] 

Bây giờ, chúng tôi có thể bỏ qua t ông tuyên bố của f và thay thế nó bằng chức năng ẩn danh,

>>> map (\x->x+1) list 
[1,2,3,4,5] 

sau đó chúng ta suy ra, đồ danh sách f == bản đồ (\ x-> x + 1) danh sách, do đó

f = \x-> x + 1 --- The same as f x = x + 1, but this is the equivalent lambda notation. 

sau đó bắt đầu với một hàm đơn giản, chúng ta sẽ thấy cách dịch nó thành một hàm ẩn danh và sau đó một hàm ẩn danh có thể dựa vào trừu tượng lambda như thế nào.

Làm bài tập thử dịch f x = 2 * x.

Bây giờ phức tạp hơn, một chức năng ẩn danh mà mất hai đối số,

Một lần nữa một ví dụ làm việc,

>>> let add x y = x + y 
>>> foldl' add 0 [0..4] 
10 

Có thể viết lại sử dụng chức năng ẩn danh như,

>>> foldl' (\x y -> x + y) 0 [0..4] 

Một lần nữa sử dụng bình đẳng chúng ta suy ra rằng add = \ xy -> x + y
Hơn nữa, trong hàm hakell, hàm số của hàm là một đối số, và chúng ta c một phần áp dụng nó, chúng ta có thể viết lại hàm ẩn danh trước đây của chúng ta như, thêm = \ x -> (\ y -> x + y).

Vậy đâu là mẹo ?? Bởi vì, tôi chỉ cho thấy việc sử dụng hàm ẩn danh thành một thứ tự cao, và bắt đầu từ đó, cho thấy cách khai thác này có thể được khai thác để viết lại hàm bằng cách sử dụng ký pháp lambda. Tôi có nghĩa là làm thế nào nó có thể giúp bạn tìm hiểu làm thế nào để viết ra chức năng vô danh?

Đơn giản là vì tôi đã cung cấp cho bạn (hiển thị cho bạn) khung hiện có bằng chức năng đặt hàng cao.
Khung làm việc này là cơ hội lớn để bạn có thể sử dụng ký hiệu này.
Bắt đầu từ đó một loạt các bài tập vô cực có thể được suy ra, ví dụ cố gắng làm như sau.

A - Find the corresponding anonymous function ? 

1 - let f (x,y) = x + y in map f [(0,1),(2,3),(-1,1)] 
2 - let f x y = x * y in foldl' f 1 [1..5] 

B - Rewrite all of them using lambda notation into a declarative form (f = \x-> (\y-> ...) 

Và vân vân ....


Để tóm tắt,

Một chức năng như

(F0) f x1 x2 ... xn = {BODY of f} 

luôn có thể được viết lại như,

(F1) f = \x1 x2 ... xn -> {BODY of f} 

nơi

(F2) (\x1 x2 ... xn -> {BODY of f}) 

hình thức F2 chỉ là chức năng ẩn danh, một bản dịch tinh khiết của hàm thành dạng phép tính lambda. F1 là một ký hiệu lambda khai báo (vì chúng ta khai báo f, như chúng ta định nghĩa nó, ràng buộc nó với F2 ẩn danh). F0 là ký hiệu thông thường của Haskeller.

Một lưu ý cuối cùng tập trung vào thực tế chúng tôi có thể đặt dấu ngoặc đơn giữa các đối số, điều này tạo ra một đóng cửa. Làm điều đó có nghĩa là một tập hợp con của mã của hàm có thể được đánh giá đầy đủ bằng cách sử dụng một tập con của đối số của hàm, (nghĩa là chuyển đổi thành một biểu mẫu không có biến tự do nào xảy ra), nhưng đó là một câu chuyện khác.

2

Từ những gì tôi hiểu các hàm Labmbda/Ẩn danh giúp bạn khai báo hàm "nội tuyến" mà không cần đặt tên cho nó. "\" (ASCII cho tiếng Hy Lạp, λ) đứng trước tên biến cho biểu thức theo sau "->". Ví dụ:

(\x y -> x + y) 

là hàm ẩn danh (lambda) tương tự như (+). Phải mất hai tham số kiểu Num và trả về tổng của chúng:

Prelude> :type (+) 
(+) :: Num a => a -> a -> a 

Prelude> :type (\x y -> x + y) 
(\x y -> x + y) :: Num a => a -> a -> a 

dụ của bạn không hoạt động bởi vì, như những người khác đã chỉ ra, ở phía bên tay phải của nó là sử dụng một hàm lambda, (\ xy -> x + y), như một tham số cho toán tử (+), được định nghĩa theo mặc định chỉ cho các tham số kiểu Num. Một số vẻ đẹp của hàm lambda có thể được sử dụng "vô danh" của nó. Vladimir đã chỉ ra cách bạn có thể sử dụng hàm lambda trong khai báo của bạn bằng cách chuyển nó qua các biến từ phía bên trái. Một sử dụng "vô danh" hơn có thể đơn giản gọi nó, với các biến, mà không đưa cho hàm một tên (do đó ẩn danh). Ví dụ,

Prelude> (\x y z -> x + y + z) 1 2 3 
6 

and if you like writing parentheses: 

Prelude> (((+).) . (+)) 1 2 3 
6 

Hoặc trong một biểu thức dài hơn (như trong ví dụ của bạn khai), ví dụ:

Prelude> filter (\x -> length x < 3) [[1],[1,2],[1,2,3]] 
[[1],[1,2]] 
Các vấn đề liên quan