2013-04-03 18 views
8

Tôi biết

$ :: (a->b) -> a -> b 
f $ x = f x 

trực giác có vẻ như với tôi, muốn nói, 1. $ trì hoãn việc đánh giá các chức năng để trái của nó 2. đánh giá whats bên phải của nó 3. feeds kết quả của nó trái sang phải.

Và nó làm cho cảm giác hoàn hảo đối với tôi khi nào,

ghci> length $ [1..5] 
5 
ghci> ($) length [1..5] 
5 

Những gì tôi không hiểu là tại sao,

ghci> ($ [1..5]) length 
5 

Đánh giá từ các loại $, không phải là của mình (lần đầu tiên) đối số nên là một hàm?

+13

Đây không phải là về '($)', mà là về các toán tử. – phg

+9

'$' * không * trì hoãn việc đánh giá hàm này sang trái. Bạn có thể nhầm lẫn nó với '$!', Điều này buộc một phần đánh giá đối số về bên phải của nó trước khi đưa nó vào hàm ở bên trái của nó. – dave4420

+0

Đây là cú pháp "phần" tại nơi làm việc. http://www.haskell.org/onlinereport/haskell2010/haskellch3.html#x8-300003.5 –

Trả lời

15

Điều này phải làm với phân tích cú pháp. Trong Haskell, bạn có thể viết (op arg) trong đó op là một toán tử kết hợp. Điều này không giống như ((op) arg). Và bạn cũng có thể viết (arg op)! Ví dụ:

GHCi, version 7.0.3: http://www.haskell.org/ghc/ :? for help 
Prelude> :t (+ 4) 
(+ 4) :: Num a => a -> a 
Prelude> :t (4 +) 
(4 +) :: Num a => a -> a 

Đó là, (+ 4) là hàm \x -> x + 4(4 +) là hàm \y -> 4 + y. Trong trường hợp bổ sung, đây là những chức năng bình đẳng, nhưng điều đó không thực sự quan trọng ngay bây giờ.

Bây giờ chúng ta hãy thử các mẹo cùng trên $:

Prelude> :t ($ [1,2,3,4]) 
($ [1,2,3,4]) :: Num t => ([t] -> b) -> b 

Bây giờ sự ngạc nhiên cho đến nay, chúng tôi đã nhận \f -> f $ [1,2,3,4]. Chúng tôi cũng có thể viết

Prelude> :t (length $) 
(length $) :: [a] -> Int 

để nhận hàm \l -> length $ l. Nhưng làm thế nào về điều này:

Prelude> :t ($ length) 
($ length) :: (([a] -> Int) -> b) -> b 

Điều này thật kỳ lạ nhưng có ý nghĩa! Chúng tôi đã nhận được \f -> f $ length, tức là, một chức năng dự kiến ​​sẽ nhận được chức năng f loại ([a] -> Int) -> b) sẽ được áp dụng cho length. Có khả năng thứ tư:

Prelude> :t ([1,2,3,4] $) 

<interactive>:1:2: 
    Couldn't match expected type `a0 -> b0' with actual type `[t0]' 
    In the first argument of `($)', namely `[1, 2, 3, 4]' 
    In the expression: ([1, 2, 3, 4] $) 

Mọi thứ phải vì [1,2,3,4] không phải là chức năng. Nếu chúng tôi viết $ trong ngoặc đơn thì sao? Sau đó, ý nghĩa đặc biệt của nó như là một nhà điều hành ghi biến mất:

Prelude> :t (($) length) 
(($) length) :: [a] -> Int 

Prelude> :t (($) [1,2,3,4]) 
<interactive>:1:6: 
    Couldn't match expected type `a0 -> b0' with actual type `[t0]' 
    In the first argument of `($)', namely `[1, 2, 3, 4]' 
    In the expression: (($) [1, 2, 3, 4]) 

Prelude> :t (length ($)) 
<interactive>:1:9: 
    Couldn't match expected type `[a0]' 
       with actual type `(a1 -> b0) -> a1 -> b0' 
    In the first argument of `length', namely `($)' 
    In the expression: (length ($)) 

Prelude> :t ([1,2,3,4] ($)) 
<interactive>:1:2: 
    The function `[1, 2, 3, 4]' is applied to one argument, 
    but its type `[t0]' has none 
    In the expression: ([1, 2, 3, 4] ($)) 

Vì vậy, để trả lời câu hỏi của bạn: $ [1,2,3,4] được phân tách như \f -> f $ [1,2,3,4] nên nó làm cho cảm giác hoàn hảo để áp dụng nó vào length. Tuy nhiên ($) [1, 2, 3, 4] không có ý nghĩa nhiều bởi vì ($) không được xem như là một toán tử infix.

Nhân tiện, $ không "không làm gì cả", để nói. Nó được sử dụng chủ yếu cho đầu vào dễ đọc hơn vì nó có ưu tiên thấp và vì vậy chúng tôi có thể viết f $ g $ h $ x thay vì f (g (h x)).

+1

'-' có thể là một lựa chọn không hợp lệ, vì nó là ngoại lệ một và duy nhất mà' (op arg) 'không * không * đại diện cho một hàm. –

+1

Ngoài ra, cả hai '((-) 4)' và '(4 -)' đều có cùng chức năng, '(\ x -> 4 - x)'. –

+0

Có nghĩa là vì (-) được liên kết trái, cả hai ((-) 4) và (4 -) có nghĩa là (\ x -> 4 - x), trong khi ($) là đúng, cả ($ func) và ($ arg) có nghĩa là (\ x -> thanh $ a) trong đó một phương tiện func hoặc arg? – Znatz

10

Câu hỏi của bạn thực sự về những gì được gọi là các toán tử. Với bất kỳ toán tử nào trong Haskell (tôi sẽ sử dụng + làm ví dụ), bạn có thể viết một cái gì đó như (+ arg) hoặc (arg +). Đây chỉ là cú pháp viết tắt cho các hàm ẩn danh (\x -> x + arg)(\x -> arg + x), tương ứng.

Vì vậy, cú pháp ($ [1..5]) chỉ có nghĩa là (\x -> x $ [1..5]) giống như (\x -> x [1..5]) (nghĩa là một hàm vượt qua [1..5] đến hàm được chuyển làm đối số của nó).

+0

Điều này (\ x -> x $ [1..5]) thực sự xóa bỏ sự nhầm lẫn của tôi! – Znatz