Tại sao truy cập System.Info không được coi là hoạt động IO trong Haskell?


25

Trong mô-đun System.Infotôi thấy các chức năng này:

os :: String
arch :: String
compilerName :: String
compilerVersion :: Version

Tại sao không IOcó ở đó? Họ đang truy cập hệ thống ... Tôi có sai không? Kỳ vọng của tôi là một cái gì đó như:

os :: IO String
arch :: IO String
compilerName :: IO String
compilerVersion :: IO Version

Trường hợp sử dụng:

      print os            -- "darwin"
      print arch          -- "x86_64"
      print compilerName  -- "ghc"

Câu trả lời:


29

Bạn không nhận được thông tin đó trong thời gian chạy . Chúng được mã hóa cứng trong trình biên dịch như được cài đặt trên hệ thống của bạn.

Điều này là rõ ràng nhất nếu bạn nhìn vào định nghĩa compilerNamenhư được tìm thấy trong http://hackage.haskell.org/package/base-4.12.0.0/docs/src/System.Info.html .

compilerName :: String
compilerName = "ghc"

nhưng thậm chí một cái gì đó như os

os :: String
os = HOST_OS

được định nghĩa theo tên không xác định khác HOST_OS(giá trị bắt đầu bằng chữ in hoa ??) cho thấy đó chỉ là một trình giữ chỗ được thay thế trong khi cài đặt.

Ai đó cũng có thể sửa tôi (xin vui lòng!), Nhưng {-# LANGUAGE CPP #-}pragma ở đầu tập tin đó gợi ý rằng HOST_OSvà những thứ tương tự được thay thế bằng các chuỗi thích hợp bởi bộ tiền xử lý C trước khi biên dịch.


2
Nếu OP thực sự muốn một số thứ IOtrong đó, thì có một trình bao bọc uname(3)có sẵn trên Hackage: hackage.haskell.org/package/bindings-uname
thsutton

19

Câu hỏi là một trong những tốt. Câu trả lời, chẳng hạn như, là các giá trị đó là tĩnh trên mỗi quá trình biên dịch chương trình. Chúng chủ yếu được biên soạn vào chương trình, và không bao giờ thay đổi sau đó. Như vậy, không có gì (trong các giả định mà GHC sử dụng) phá vỡ nếu bạn coi chúng là hằng số. Và sẽ thuận tiện hơn khi sử dụng hằng số đơn giản hơn là hành động IO.

Nhưng đó là tất cả các loại lý luận di sản. Haskell là một ngôn ngữ cũ. (Không thực sự, nó cũ hơn Java vài năm.) Rất nhiều thư viện đã được xây dựng với lý luận không còn được coi là thực tiễn tốt nhất. Đây là những ví dụ về điều đó. Một thư viện hiện đại phơi bày chúng có thể sẽ khiến chúng hoạt động IO mặc dù kết quả không thay đổi sau khi biên dịch. Sẽ hữu ích hơn khi đặt những thứ không phải là hằng số ở mức nguồn phía sau các hành động IO, mặc dù vẫn có một số ngoại lệ đáng chú ý, như Intthay đổi kích thước giữa các nền tảng 32 và 64 bit.

Trong mọi trường hợp ... Tôi muốn nói rằng kỳ vọng của bạn là vững chắc, và những kiểu đó là kết quả của những điều kỳ lạ trong lịch sử.


-9

EDIT: Cảm ơn @interjay và @Antal Spector-Zabusky vì đã giải thích lý do tại sao câu trả lời này bị từ chối. Họ viết

Các tài liệu là một chút sai lệch. Các giá trị được mã hóa cứng vào trình biên dịch GHC. Sau 48 năm bạn chắc chắn biết rằng mã thực tế luôn vượt qua tài liệu. - interjay ngày hôm qua @ andy256 Bạn hoàn toàn đúng khi tài liệu đó tệ (thực sự, đó là một phần lý do tại sao Francisco hỏi câu hỏi này ngay từ đầu), và sự nhầm lẫn của bạn là điều dễ hiểu. Vấn đề của Haskell là nếu các giá trị Chuỗi đó có thể thay đổi trong thời gian chạy, thì đó sẽ là một lỗi nghiêm trọng - các biến không được phép thay đổi. Đây là tầm quan trọng của hàm tạo kiểu IO - nó đại diện cho một tính toán được phép truy cập vào "thế giới bên ngoài", và do đó, một kết quả có thể thay đổi. Thực hiện cuộc gọi hệ thống là một ví dụ tốt về hành động IO. Tiết [1/2] - Antal Spector-Zabusky 9 giờ trước @ andy256 Mạnh (Một hành động IO khác có thể là "cập nhật bộ đếm toàn cầu".) Vì vậy, khi chúng tôi thấy một Chuỗi, chúng tôi biết rằng nó không thể thực hiện bất kỳ giao tiếp nào với HĐH dưới mui xe. Đây là lý do tại sao, có lẽ đáng ngạc nhiên nếu bạn không quen với Haskell, sẽ không dễ thực hiện os :: String để thực hiện cuộc gọi hệ thống - mọi giá trị như vậy đều không thể thực hiện được trong Haskell cơ bản, sẽ vi phạm mọi kỳ vọng của lập trình viên về cách các chương trình làm việc và thậm chí có khả năng tăng tốc trình biên dịch và trình tối ưu hóa (không phải là vấn đề lý thuyết - có câu trả lời Stack Overflow nơi mọi người gặp vấn đề tương tự). [2/2] - Antal Spector-Zabusky Đây là lý do tại sao, có lẽ đáng ngạc nhiên nếu bạn không quen với Haskell, sẽ không dễ thực hiện os :: String để thực hiện cuộc gọi hệ thống - mọi giá trị như vậy đều không thể thực hiện được trong Haskell cơ bản, sẽ vi phạm mọi kỳ vọng của lập trình viên về cách các chương trình làm việc và thậm chí có khả năng tăng tốc trình biên dịch và trình tối ưu hóa (không phải là vấn đề lý thuyết - có câu trả lời Stack Overflow nơi mọi người gặp vấn đề tương tự). [2/2] - Antal Spector-Zabusky Đây là lý do tại sao, có lẽ đáng ngạc nhiên nếu bạn không quen với Haskell, sẽ không dễ thực hiện os :: String để thực hiện cuộc gọi hệ thống - mọi giá trị như vậy đều không thể thực hiện được trong Haskell cơ bản, sẽ vi phạm mọi kỳ vọng của lập trình viên về cách các chương trình làm việc và thậm chí có khả năng tăng tốc trình biên dịch và trình tối ưu hóa (không phải là vấn đề lý thuyết - có câu trả lời Stack Overflow nơi mọi người gặp vấn đề tương tự). [2/2] - Antal Spector-Zabusky và thậm chí có khả năng tăng trình biên dịch và trình tối ưu hóa (không phải là vấn đề lý thuyết - có câu trả lời Stack Overflow nơi mọi người gặp vấn đề tương tự). [2/2] - Antal Spector-Zabusky và thậm chí có khả năng tăng tốc trình biên dịch và trình tối ưu hóa (không phải là vấn đề lý thuyết - có câu trả lời Stack Overflow nơi mọi người gặp vấn đề tương tự). [2/2] - Antal Spector-Zabusky

Nó hiện có hai phiếu xóa. Tôi sẽ để quá trình đó diễn ra, nhưng đề nghị nó thực sự có giá trị. Bên cạnh đó, những lời giải thích của họ cho thấy câu hỏi rất yếu và câu trả lời cũng vậy, vì một người mới chơi Haskell có thể dễ dàng làm theo lý do mà tôi đã làm.

Câu trả lời gốc:

Tôi không phải là lập trình viên Haskell, nhưng hai câu trả lời đã được đưa ra không khớp với tài liệu mà OP liên kết.

Giải thích của tôi về các tài liệu sau đây.

os :: String - Điều này cung cấp cho bạn "Hệ điều hành mà chương trình đang chạy."

Tôi hy vọng rằng điều này sẽ đưa ra một cuộc gọi hệ thống để có được thông tin. Bởi vì hệ thống mà chương trình được biên dịch có thể khác với hệ thống mà nó chạy trên nó không thể là một giá trị được chèn bởi trình biên dịch. Nếu mã đang được diễn giải thì trình thông dịch có thể cung cấp kết quả, phải được lấy thông qua một cuộc gọi hệ thống.

arch :: String - Điều này cung cấp cho bạn "Kiến trúc máy mà chương trình đang chạy."

Một lần nữa, tôi hy vọng rằng điều này sẽ đưa ra một cuộc gọi hệ thống để có được thông tin. Bởi vì hệ thống mà chương trình được biên dịch có thể khác với hệ thống mà nó chạy trên nó không thể là một giá trị được chèn bởi trình biên dịch.

compilerName :: String - Điều này mang đến cho bạn "Việc triển khai Haskell mà chương trình được biên dịch hoặc đang được diễn giải."

Giá trị này chắc chắn được chèn bởi trình biên dịch / trình thông dịch.

compilerVersion :: String- Điều này mang đến cho bạn "Phiên bản compilerNamemà chương trình được biên dịch hoặc đang được diễn giải."

Giá trị này chắc chắn được chèn bởi trình biên dịch / trình thông dịch.

Mặc dù bạn có thể xem xét hai cuộc gọi đầu tiên để có được đầu vào, kết quả đến từ các giá trị được giữ bởi Hệ điều hành. I / O thường đề cập đến truy cập lưu trữ thứ cấp.


3
Nó không đúng với haskell. Ở đây mọi tính toán đều không có thứ tự và kết quả của chúng có thể được lưu trữ. Các hàm là thuần túy, vì vậy nếu một hàm chấp nhận không có đối số, thì nó giống như một hằng số. Các hàm của một arg trông giống như chỉ là hashmap hoặc từ điển, tính toán giá trị dựa trên khóa. Bạn không thể sử dụng môi trường bên ngoài, làm các tòa nhà trong các chức năng như vậy, thậm chí bạn không thể có được một số ngẫu nhiên hoặc ngày hiện tại. Nhưng nếu bạn thực sự muốn sử dụng "trình tự" hoặc môi trường đó, thì bạn cần sử dụng IOđơn nguyên để mô phỏng trạng thái, mô phỏng trình tự hoạt động
Yuri Kovalenko

"Bạn không thể sử dụng môi trường bên ngoài, tạo các tòa nhà trong các chức năng như vậy" - Chắc chắn bạn có thể, đặc biệt nếu "bạn" là trình biên dịch Haskell! Sẽ rất dễ dàng để triển khai Haskell thực hiện os :: Stringđể nó thực hiện cuộc gọi hệ thống khi được đánh giá.
Tanner Swett

2
Tôi không nghĩ bạn hiểu tầm quan trọng của đơn vị IO trong Haskell.
Sneftel

@Sneftel Tất nhiên là đúng rồi. Tôi đã chọn trả lời vì sau 48 năm lập trình trong mọi mô hình và viết trình biên dịch kỳ quặc, các câu trả lời ban đầu không khớp với tài liệu và chúng vẫn không. Nó nói rõ rằng osarchthu được trong thời gian chạy.
andy256

1
Các tài liệu là một chút sai lệch. Các giá trị được mã hóa cứng vào trình biên dịch GHC. Sau 48 năm bạn chắc chắn biết rằng mã thực tế luôn vượt qua tài liệu.
interjay
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.