io - अगदा: कोरिंग के बजाय स्ट्रिंग के रूप में मानक इनपुट की एक पंक्ति पढ़ना




agda (2)

# एगडा पर सैज़ान बताते हैं कि एक ही मिल सकता है कि getLine : IO String बजाय getLine : IO Costring यह काम। तो आप प्राप्त करें:

module EchoInputReverse where

-- Agda standard library 0.7
open import Data.List using (reverse)
open import Data.String
open import Foreign.Haskell using (Unit)
open import IO.Primitive

postulate
  getLine : IO String

{-# COMPILED getLine getLine #-}

main : IO Unit
main = 
  getLine >>= (λ s → 
  return (toCostring (fromList (reverse (toList s)))) >>= (λ s' → 
  putStrLn s'))

नकारात्मक पक्ष यह है कि यह दृष्टिकोण यह दावा करता है कि getLine हमेशा एक परिमित स्ट्रिंग देता है, जो कि getLine के मामले में सही नहीं हो सकता है prog < /dev/zero @Vitus बिंदुओं के अनुसार

लेकिन मुझे नहीं लगता कि यह मामला है यदि getLine वास्तव में एक अनंत स्ट्रिंग देता है तो न तो यह समाधान और न ही विटस का समाधान एक प्रोग्राम को समाप्त करेगा जो समाप्त हो जाएगा। उनके पास समान व्यवहार है

यह पता लगाने के लिए आदर्श होगा कि इनपुट अनंत था और उस मामले में कोई त्रुटि उत्पन्न हुई। लेकिन आईओ पर इस तरह की अनन्तता का पता लगाने सामान्य रूप से संभव नहीं है।

मैं एक साधारण प्रोग्राम लिखने का प्रयास कर रहा हूं जो मानक इनपुट से एक पंक्ति को पढ़ता है, इसे उलट करता है, और फिर उलट स्ट्रिंग प्रिंट करता है।

दुर्भाग्यवश, देशी getLine फ़ंक्शन एक Costring पढ़ता है; मैं केवल String रिवर्स कर सकता हूं; और कोई ऐसा कार्य नहीं है जो String को Costring लेता है

संकलित करने के लिए मैं इस कार्यक्रम को कैसे संशोधित कर सकता हूं?

module EchoInputReverse where

-- Agda standard library 0.7
open import Data.List using (reverse)
open import Data.String
open import Foreign.Haskell using (Unit)
open import IO.Primitive

postulate
  getLine : IO Costring

{-# COMPILED getLine getLine #-}

main : IO Unit
main = 
  getLine >>= (λ s → 
  -- NOTE: Need a (toString : Costring → String) here. Or some other strategy.
  return (toCostring (fromList (reverse (toList (toString s))))) >>= (λ s' → 
  putStrLn s'))

आप ऐसा नहीं कर सकते, कम से कम सीधे नहीं। समस्या यह है कि Costring आकार में अनंत हो सकती है, जबकि String को परिमित होना चाहिए।

प्रोग्राम को प्रोग्राम के रूप में चलाने की कल्पना करें prog < /dev/zero , क्या होना चाहिए? reverse फ़ंक्शन इनपुट सूची के अंत तक पहुंचने के बाद ही पहला तत्व बना सकता है और ऐसा कभी नहीं हो सकता।

हमें इस तथ्य को व्यक्त करने की आवश्यकता है कि Costring से String को परिवर्तित करने में विफल हो सकते हैं। ऐसा करने का एक तरीका पक्षपाती मोनद का उपयोग करना है चलो परिभाषा को देखें:

data _⊥ {a} (A : Set a) : Set a where
  now   : (x : A) → A ⊥
  later : (x : ∞ (A ⊥)) → A ⊥

इसलिए, हम या तो एक प्रकार का मूल्य now कर सकते now , या हमें later इंतजार करना होगा लेकिन प्रतीक नोटिस: जिसका अर्थ है कि हम वास्तव में हमेशा के लिए इंतजार कर सकते हैं (जैसा कि later अनंत निर्माणाकों की अनंत संख्या हो सकती है)।

मैं रूपांतरण को मर्ज करूँगा और एक फ़ंक्शन में पीछे करूँगा। पहले आयात करें:

open import Category.Monad.Partiality
open import Coinduction
open import Data.Char
open import Data.Colist
  using ([]; _∷_)
open import Data.List
  using ([]; _∷_; List)
open import Data.String
open import Data.Unit
open import IO

अब, हमारे reverse फ़ंक्शन का प्रकार यह उल्लेख करना चाहिए कि हम एक Costring एक इनपुट के रूप में लेते हैं, लेकिन यह भी कि String वापस करने में विफल हो सकता है। कार्यान्वयन काफी सरल है, यह संचायक के साथ सामान्य रिवर्स है:

reverse : Costring → String ⊥
reverse = go []
  where
  go : List Char → Costring → String ⊥
  go acc []       = now (fromList acc)
  go acc (x ∷ xs) = later (♯ go (x ∷ acc) (♭ xs))

हालांकि, हम एक String मुद्रित कर सकते हैं, लेकिन String ⊥ नहीं String ⊥ ! यही वह जगह है जहां IO मदद करता है: हम later कन्स्ट्रक्टरों को "कुछ भी नहीं" के रूप में व्याख्या कर सकते हैं और अगर हम now कन्स्ट्रक्टर को putStrLn , तो हम String इसमें शामिल कर सकते हैं।

putStrLn⊥ : String ⊥ → IO ⊤
putStrLn⊥ (now   s) = putStrLn s
putStrLn⊥ (later s) = ♯ return tt >> ♯ putStrLn⊥ (♭ s)

सूचना है कि IO मॉड्यूल से IO उपयोग करता हूं, IO से नहीं। यह मूल रूप से पोस्ट की गई एक परत पर आधारित है, इसलिए यह थोड़ा अच्छा है। लेकिन अगर आप इस के साथ getLine का उपयोग करना चाहते हैं, तो आपको लिखना होगा:

import IO.Primitive as Prim

postulate
  primGetLine : Prim.IO Costring

{-# COMPILED primGetLine getLine #-}

getLine : IO Costring
getLine = lift primGetLine

और अंत में, हम main फ़ंक्शन लिख सकते हैं:

main = run (♯ getLine >>= λ c → ♯ putStrLn⊥ (reverse c))

इस प्रोग्राम को Cc Cx Cc जरिए Cc Cx Cc और उसके बाद चलाना, हम उम्मीद करते हैं:

$ cat test
hello world
$ prog < test    
dlrow olleh