2013-04-04 34 views
6

Chỉ là một câu hỏi khái niệm nhanh, tôi hiện đang cố gắng tìm hiểu và hiểu rõ hơn về Haskell.Tại sao không có trường hợp Hiển thị cho các chức năng?

Tôi biết chức năng Hiển thị được sử dụng để chuyển đổi giá trị thành chuỗi, nhưng tại sao các loại chức năng không thể được sử dụng với chương trình?

Prelude> (\x -> x*3) 

<interactive>:7:1: 
    No instance for (Show (a0 -> a0)) 
     arising from a use of `print' 
    Possible fix: add an instance declaration for (Show (a0 -> a0)) 
    In a stmt of an interactive GHCi command: print it 
Prelude> 
+0

Bạn muốn tạo ra 'Chuỗi' nào cho hàm đó? –

Trả lời

10

Nó không phải là họ không thể, nhưng đó thường không phải là một lý do chính đáng để.

Nhưng nếu bạn muốn, bạn chắc chắn có thể:

Prelude> :{ 
Prelude| instance Show (a -> b) where 
Prelude| show _ = "A function." 
Prelude| :} 
Prelude> print (\x -> x + 7) 
A function. 
Prelude> print (\a b c -> a + b + c) 
A function. 

Nếu bạn muốn show các đại diện văn bản của hàm, tốt - bạn không thể làm điều đó. Không giống như các ngôn ngữ lập trình meta như Ruby, JS, vv, mã Haskell rất ít kiến ​​thức về nội bộ của riêng nó.

+2

Thực tế có một phiên bản 'Show' được tích hợp sẵn. Đây là một câu hỏi thường gặp - [ở đây] (http://stackoverflow.com/questions/15015698/derive-eq-and-show-for-type-alias-in- ví dụ: haskell/15015731 # 15015731) và [here] (http://stackoverflow.com/questions/10551210/instance-show-for-function/10551513#10551513). –

3

show là chức năng được xác định trên chức năng mà là thành viên của Show typeclass (nếu bạn không biết những gì một typeclass là, nó kinda giống như một giao diện OOP).

Theo mặc định, các chức năng không phải là thành viên của typeclass, vì vậy chúng tôi không thể in chúng.

Chúng ta có thể làm cho nó một thành viên của typeclass với

instance Show (a -> b) where 
    show f = "Unicorns!!" 

nhưng ở đây chúng tôi nhận ra lý do tại sao nó không được thực hiện theo mặc định. Không có một biểu diễn đơn giản, rõ ràng về các hàm và haskell không muốn đoán, và do đó không có cá thể nào.

Ví dụ "được phép" duy nhất là bản in thực sự chức năng, nhưng điều này sẽ yêu cầu thay đổi ngôn ngữ thực sự, nghĩa là nó sẽ được chuyển thành trình biên dịch, điều này không đáng giá đối với một vài trường hợp nó có thể hữu ích.

Hơn nữa đó là một sự thay đổi biên dịch không tầm thường, Haskell được biên dịch có nghĩa là sự khác nhau giữa một cái gì đó giống như f = g

f =    g 

đang hoàn toàn bị mất trên đó. Nhưng bạn chắc chắn muốn điều đó trong biểu diễn hàm của bạn. Bởi vì điều này, bạn sẽ phải lug quanh chuỗi này thông qua chương trình. Điều này chắc chắn không phải là những gì bạn muốn trong một nhị phân.

Nếu bạn thực sự muốn nó in kỳ lân !! mặc dù, cảm thấy tự do.

+0

Jynx! Tôi nghĩ rằng nó đáng chú ý lý do tại sao (lớn) thay đổi trình biên dịch sẽ được yêu cầu: biên dịch Haskell dải đi nhiều chi tiết của mã. – amindfv

+0

Tốt trong sự công bằng, với ghc, các ngôn ngữ trung gian giữ lại một lượng thông tin hợp lý, tuy nhiên văn bản chức năng thực tế, tức là những thứ như khoảng trắng, biến mất sau khi phân tích cú pháp và biến mất vĩnh viễn. Ps "Unicorn !!" có nhiều thông tin hơn "Hàm". : P – jozefg

+4

Một đối số cũng có thể được thực hiện theo ngữ nghĩa, '\ x -> 3 * x' và' \ x -> x * 3' là cùng một hàm (ít nhất là trên 'Int'), vì vậy bạn có thể để tùy ý chọn một chuỗi để biểu diễn cả hai hoặc làm việc trong đơn nguyên 'IO' để phân biệt giữa chúng. – hammar

7

Có một giải pháp một phần vượt xa chỉ là một chuỗi cố định cho tất cả các hàm sử dụng Data.Typeable.

{-# LANGUAGE ScopedTypeVariables #-} 

import Data.Typeable 

instance (Typeable a, Typeable b) => Show (a->b) where 
    show _ = show $ typeOf (undefined :: a -> b) 

trong ghci

> let test :: Int->Int; test x = x + x 
> test 
Int -> Int 

Thật không may mà không có một loại chữ ký loại sẽ đi đến nó mặc định.

> let test x = x + x 
> test 
Integer -> Integer 

Giải pháp này hoạt động trên nhiều arities chức năng vì a -> b -> c cũng giống như a -> (b -> c) mà bạn cũng có thể viết như a -> d nơi d = b -> c.

> let m10 a b c d e f g h i j = a * b * c * d * e * f * g * h* i * j 
> m10 
Integer -> Integer -> Integer -> Integer -> Integer -> Integer -> Integer 
     -> Integer -> Integer -> Integer -> Integer 

Phương pháp này không làm việc tuy nhiên khi nó là chưa biết nếu các thông số của hàm có lớp typeable tuy nhiên như vậy trong khi map (+1) sẽ làm việc map sẽ không.

> map (+1) 
[Integer] -> [Integer] 
> map 

<interactive>:233:1: 
... 

Sau khi liếc nhìn bên trong của Data.Data và một thí nghiệm hoặc hai nó có vẻ như nó có thể được refactored để được một chút tổng quát hơn bìa nhiều chức năng.

Các vấn đề liên quan