2012-05-15 12 views
20

Liệu nó có giúp trình biên dịch tối ưu hóa hay chỉ là công việc dư thừa để thêm chữ ký bổ sung? Ví dụ, người ta thường thấy:Tại sao việc sử dụng chữ ký kiểu trong điều khoản ở đâu lại quá hiếm thấy?

foo :: a -> b 
foo x = bar x 
     where bar x = undefined 

Thay vì:

foo :: a -> b 
foo x = bar x 
     where bar :: a -> b 
      bar x = undefined 

Nếu tôi bỏ qua chữ ký loại cấp cao nhất, GHC mang lại cho tôi một lời cảnh báo, vì vậy nếu tôi không nhận được cảnh báo tôi khá tự tin chương trình của tôi là chính xác. Nhưng không có cảnh báo nào được đưa ra nếu tôi bỏ qua chữ ký trong mệnh đề where.

+0

Tôi không thể trả lời câu hỏi có hay không sẽ biên soạn nhanh hơn, nhưng thực hành tốt nhất là viết ra chữ ký loại nếu đó là một hàm không tầm thường. – Wes

+7

Ngoài ra, nhiều định nghĩa cục bộ này cần phải truy cập các biến kiểu từ phạm vi bên ngoài, có xu hướng làm lộn xộn mã với 'asTypeOf' và bạn bè, trừ khi bạn sử dụng' ScopedTypeVariables'. – Vitus

+1

Nếu chức năng của bạn là đủ quan trọng để có được một tuyên bố loại, tại sao không làm cho nó một công dân hạng nhất? – rotskoff

Trả lời

17

Các định nghĩa thường trong mệnh đề where là để tránh lặp lại chính mình nếu một biểu thức con xuất hiện nhiều hơn một lần trong định nghĩa. Trong trường hợp này, lập trình viên nghĩ về định nghĩa cục bộ như là một stand-in đơn giản để viết ra các biểu thức con inline. Bạn thường sẽ không rõ ràng gõ các biểu thức con bên trong, vì vậy bạn không nhập định nghĩa where. Nếu bạn đang thực hiện nó để tiết kiệm khi gõ, thì việc khai báo kiểu sẽ giết tất cả các khoản tiết kiệm của bạn.

Có vẻ như khá phổ biến khi giới thiệu where cho người học Haskell với các ví dụ về biểu mẫu đó, vì vậy họ cứ nghĩ rằng "kiểu thông thường" không cung cấp các khai báo kiểu cho định nghĩa cục bộ. Ít nhất, đó là kinh nghiệm của tôi khi học Haskell. Tôi đã phát hiện ra rằng nhiều chức năng của tôi đủ phức tạp để cần một khối where trở nên khá khó hiểu nếu tôi không biết loại định nghĩa cục bộ, vì vậy tôi cố gắng hướng tới việc luôn gõ chúng ngay bây giờ; ngay cả khi tôi nghĩ loại hình hiển nhiên trong khi tôi đang viết mã, nó có thể không rõ ràng khi tôi đọc nó sau khi không xem xét nó một lúc. Một chút nỗ lực cho các ngón tay của tôi hầu như luôn luôn nặng hơn bởi một hoặc hai trường hợp phải chạy suy luận kiểu trong đầu tôi!

Câu trả lời của Ingo đưa ra lý do chính đáng cho cố ý không đưa ra loại cho định nghĩa địa phương, nhưng tôi nghi ngờ nguyên nhân chính là nhiều lập trình viên đã đồng hóa quy tắc chung. cho các định nghĩa địa phương từ cách họ học Haskell.

0

Thêm chữ ký loại có thể làm cho mã của bạn nhanh hơn. Lấy ví dụ chương trình sau đây (Fibonacci):

result = fib 25 ; 
-- fib :: Int -> Int 
fib x = if x<2 then 1 else (fib (x-1)) + (fib (x-2)) 
  • Nếu không có chú thích ở dòng thứ 2, phải mất 0.010 giây. chạy.
  • Với chú thích Int -> Int, phải mất 0,002 giây.

Điều này xảy ra bởi vì nếu bạn không nói bất cứ điều gì về fib, nó sẽ được đánh máy như fib :: (Num a, Num a1, Ord a) => a -> a1, có nghĩa là trong thời gian chạy, thêm cấu trúc dữ liệu ("từ điển") sẽ phải được thông qua giữa chức năng đại diện cho Num/Ord typeclasses.

+1

Câu hỏi hỏi về chữ ký kiểu của các định nghĩa địa phương. Nó thực sự rất phổ biến để cung cấp cho chữ ký loại để định nghĩa cấp cao nhất. – Vitus

+2

Tôi đồng ý với Vitus, câu trả lời này ít liên quan đến các định nghĩa địa phương. Việc viết các định nghĩa cấp cao nhất mà không có chữ ký loại sẽ được gán nhiều kiểu chung hơn bạn có thể cần và do đó chạy chậm hơn. Định nghĩa cục bộ hầu như luôn bị ràng buộc bởi chữ ký loại của định nghĩa cấp cao nhất mà chúng xuất hiện, do đó, vấn đề này không phát sinh gần như thường xuyên nếu bạn đang nhập định nghĩa cấp cao nhất của mình. Ngay cả khi định nghĩa cục bộ không bị ràng buộc chính thức, trình biên dịch biết nó là cục bộ và không cần phải nói chung hơn là sử dụng cục bộ của nó. – Ben

11

Thông thường, các khai báo where được sử dụng cho các nội dung ngắn, cục bộ, có các loại đơn giản hoặc các loại dễ suy luận. Kết quả là không có lợi ích cho con người hoặc trình biên dịch để thêm loại.

Nếu loại phức tạp hoặc không thể suy ra, thì bạn có thể muốn thêm loại.

Trong khi cho chữ ký kiểu đơn có thể làm cho các hàm cấp cao hơn nhanh hơn, nó không phải là một thắng lợi cho các định nghĩa địa phương trong các mệnh đề where, vì GHC sẽ nội tuyến và tối ưu hóa các định nghĩa trong hầu hết các trường hợp.

20

Có tồn tại một lớp chức năng cục bộ không thể viết bằng Haskell (không sử dụng các phần mở rộng GHC ưa thích). Ví dụ:

f :: a -> (a, Int) 
f h = g 1 
    where g n = (h, n) 

Điều này là do trong khi a trong các loại chữ ký f được đa hình nhìn từ bên ngoài f, đây không phải là như vậy từ trong f. Trong g, nó chỉ là một số loại không xác định, nhưng không phải bất kỳ loại nào và (tiêu chuẩn) Haskell không thể diễn đạt "cùng loại với đối số đầu tiên của hàm này được xác định bằng".

+4

Mặc dù '{- # LANGUAGE ScopedTypeVariables # -}' cho phép bạn cung cấp kiểu 'g :: Int -> (a, Int)' nếu bạn sửa đổi chữ ký kiểu cho 'f' thành' forall a. a -> (a, Int) '. –

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