2011-01-26 12 views
5

मैं बस हास्केल के साथ शुरू कर रहा हूं और सीज़र साइफर बनाने के लिए एक अच्छा exercise समाप्त कर चुका हूं।सूची समझ के बजाय उपयोग करने के लिए

पहले चरण में से एक ऐसा कार्य करना था जो एक पत्र लेगा और इसे एक संख्या में बदल देगा। मुझे पता है कि chr और ord पहले से ही ऐसा कर सकते हैं लेकिन अभ्यास का हिस्सा स्वयं लिखना था।

let2num c = head [ b | (a,b) <- zip ['a'..'z'] [0..25], a==c] 

मैं, हास्केल वाक्य रचना और पहली बातें मैंने सीखा सूची comprehensions था से एक के लिए नया हूँ ताकि मेरे हथौड़ा बन गया है। हालांकि मैं बहुत उत्सुक हूं, इस समारोह को लिखने के लिए एक और (संभवतः बेहतर) तरीका क्या है?

यदि आप उत्सुक हैं तो शेष सिफर gist में है।

संपादित

मैं भी अन्य तरीकों से संख्या से पत्र को वापस अनुवाद करने के लिए इच्छुक हूँ।

num2let d = head [ a | (a,b) <- zip ['a'..'z'] [0..25], b==(d `mod` 26)] 
+0

मुझे आश्चर्य है कि 'अगर सिर [ख | (ए, बी) <- ज़िप ['ए' .. 'जेड'] [0..25], एक == सी] 'ओ (2 एन + 1) है। –

+0

@Yasir: कड़ाई से यह ओ (1) बोल रहा है, क्योंकि केवल 26 निचले मामले पत्र हैं। लेकिन हाँ, यह बहुत कुशल नहीं है। मेरा जवाब देखें –

+0

@Roman: लेकिन यह पहली बार ज़िपित सूची बनाता है, फिर संतोषजनक 'एक == c' तत्वों की एक और सूची बनाता है, फिर एक तत्व निकालता है: काफी काम का एक बहुत यह विचार करने के लिए हे (1), हुह। :-) हालांकि हो सकता है कि मैं गलत हूं। –

उत्तर

4

मेरे समाधान:

import Data.List 
let2num c = let (Just n) = elemIndex c ['a'..'z'] in n 

या:

import Data.List 
import Data.Maybe 
let2num c = fromJust $ elemIndex c ['a'..'z'] 

या pointless style में:

import Data.List 
import Data.Maybe 
let2num = fromJust . (flip elemIndex) ['a'..'z'] 

समारोह elemIndex पहले ELEM के सूचकांक रिटर्न दिए गए सूची में जो बराबर है (== द्वारा) क्वेरी तत्व में, या Nothing यदि कोई ऐसा तत्व नहीं है।

Maybe प्रकार वैकल्पिक मान को समाहित करता है। Maybe a के प्रकार का मान या तो a (Just a के रूप में प्रतिनिधित्व किया गया) का मान है, या यह खाली है (Nothing के रूप में प्रतिनिधित्व किया गया है)। Maybe का उपयोग त्रुटियों या असाधारण मामलों से निपटने का एक अच्छा तरीका है जैसे कि त्रुटि जैसे कठोर उपायों का उपयोग किए बिना।

फ़ंक्शन fromJustJust से तत्व निकालता है।

+0

+1 धन्यवाद! मुझे कुछ समझने की ज़रूरत होगी कि सबकुछ क्या है, लेकिन यह बहुत उपयोगी है। – lashleigh

+0

रिवर्स प्रक्रिया पर कोई विचार? एक नंबर से वापस एक पत्र में जाने पर मुझे नहीं लगता कि elemIndex मदद करेगा। – lashleigh

+2

मैं देख रहा हूँ कि क्यों वे यह 'fromJust' नामित के रूप में' unJust' करने का विरोध किया;) –

3

"सीज़र ने वर्णमाला के अंत में चारों ओर लपेटकर वर्णमाला के नीचे तीन स्थानों को पत्र में प्रत्येक अक्षर को प्रतिस्थापित किया।" हम इसे हास्केल में लिख सकते हैं। वास्तव में हम let2num और num2let से पूरी तरह से बच सकते हैं।,

cipher = let abc = ['a'..'z'] 
      code = drop 3 abC++ take 3 abc 
     in zip abc code 

ऐसा लगता है कि

[('a','d'),('b','e'),('c','f'),('d','g'), ... ] 

देखो अब हम एक प्रतीक एन्क्रिप्ट कर सकते हैं होगा अगर हम बस:

तो चलो एक मेज को परिभाषित करने सिफर पाठ वर्णमाला में सादे पाठ वर्णमाला मैप करने के लिए के साथ शुरू करते हैं इस शब्दकोश में lookup पत्र:

ghci> lookup 'a' cipher 
Just 'd' 

lookup रिटर्न एक Maybe Char मूल्य, हम इसे बदलने की आवश्यकता बस एक Char, और इस के लिए मैं maybe फ़ंक्शन का उपयोग करें, पाया प्रतीकों को प्रतीकों के लिए '?' जो सिफर में नहीं पाए गए, और id (पहचान समारोह = कोई बदलाव नहीं) का उपयोग कर रहे हैं:

ghci> maybe '?' id (lookup 'a' cipher) 
'd' 

अब हम सिर्फ एक प्रतीक सांकेतिक शब्दों में बदलना करने के लिए एक encrypt समारोह में लिख सकते हैं, यह एक अंतरिक्ष जैसे पात्रों लापता छोड़ देंगे,, एन्क्रिप्ट नहीं किए गए:

encrypt c = maybe c id (lookup c cipher) 

एक पूरे स्ट्रिंग एन्क्रिप्ट करने के लिए:

+०१२३५१६४१०
ghci> map encrypt "haskell is fun" 
"kdvnhoo lv ixq" 

इसलिए हम सभी को एक साथ रख सकते हैं:

encrypt c = maybe c id (lookup c cipher) 
    where 
    cipher = let abc = ['a'..'z'] 
       code = drop 3 abC++ take 3 abc 
      in zip abc code 
+0

मैंने पढ़ा है कि आप 'लिखने के let2num' समारोह चाहते हैं और मान लिया है कि आप इसे प्रतिस्थापन बीजलेख लागू करना चाहते हैं। मैं यह दिखाना चाहता था कि सिफर को क्रमिक संख्याओं की स्पष्ट गणना के बिना लागू किया जा सकता है, बल्कि अनुवाद तालिका के साथ। – sastanin

+0

हां, अंतिम लक्ष्य एक प्रतिस्थापन सिफर था, लेकिन यदि आप पूरा प्रश्न पढ़ते हैं, तो आप देखेंगे कि वास्तविक प्रश्न अनिवार्य रूप से था "स्क्रैच से num2let लिखने का बेहतर तरीका क्या है, बिना chr और ord?) – Benson

4

रिवर्स प्रक्रिया:

num2let = (!!) ['a'..'z'] 

!! एक List index (subscript) operator है, 0 से शुरू। यह अधिक सामान्य Data.List.genericIndex का एक उदाहरण है, जो किसी भी अभिन्न प्रकार का सूचकांक लेता है।

(!!)partially applied यहाँ जिसका मतलब है कि यह अभी भी प्रकार Int में से एक तर्क की जरूरत है परिणाम (एक मूल्य सूची जिसका सूचकांक Int मूल्य आप num2let को पारित करने के बराबर होती है) से उपज के लिए है।

+0

यह शानदार है दुर्भाग्यवश मैं केवल आपके उत्तरों में से एक स्वीकार कर सकता हूं :) – lashleigh

+0

यह शायद ओ (1) है। नहीं? –

+0

कड़ाई से बोल रहा है, हां, मूल था (रोमन की टिप्पणी देखें)। लेकिन यदि आपका मतलब है कि यह अधिक कुशल होना चाहिए (मैं एक सरणी का प्रयोग करेंगे) मूल, नहीं काफ़ी, क्योंकि आप अभी भी '25' के रूप में '0' परिवर्तित करने के लिए एक लिंक की गई सूची traversing कर रहे हैं। आप कदम की एक ही नंबर के लिए चाहते हैं, आप एक अलग डेटा संरचना की आवश्यकता होगी । –

0

मुझे यकीन नहीं है कि आप ord समाधान का विरोध क्यों कर रहे हैं। सूची-आधारित समाधान अनावश्यक काम करते हैं (एक सूची को घुमाते हैं)। और की एक विधि, Enum वर्ग की एक विधि है जो एस और Char एस के बीच ord/chr डू के रूप में परिवर्तित करने की अनुमति देती है। यह Char प्रकार के लिए प्रदान किया गया निम्नतम स्तर का इंटरफ़ेस है, इसलिए आप शायद ही कभी "अपना खुद का लिखें" कर सकते हैं (मुक्केबाजी/स्वयं को अनबॉक्सिंग करने के अलावा, लेकिन यह एक बड़ी खुशी नहीं है)।

+0

@Roman –

+1

@ यासीर: वे * यूनिकोड के लिए काम करते हैं, क्योंकि 'चर' बस एक यूनिकोड कोड बिंदु है। उदा .: 'ord 'ы'' ->' 1099' –

+0

@Roman: हेहे वास्तव में, काफी 'भूल Data.Char' यूनिकोड-वाकिफ हैं। –

2

पूर्णता के लिए, मुझे लगता है कि किसी को यह उल्लेख करना चाहिए कि सूची की समझ सूची मोनैड में सामान लिखने के लिए सिर्फ एक शॉर्टकट है। आपका कोड प्रतिबिंबित है, मोटे तौर पर, यह:

let2num c = head $ do (a,b) <- zip ['a'..'z'] [0..25] 
         if a == c then [b] else [] 

एक बहुत ही रोचक उदाहरण नहीं है, लेकिन आप वहां जाते हैं।

इसके अलावा, de-sugaring वाक्य रचना करते हैं, यह एक ही है:

let2num c = head $ zip ['a'..'z'] [0..25] >>= \(a,b) -> if a == c then [b] else [] 
+0

+1 धन्यवाद, यह एक बहुत ही उपयोगी तुलना के लिए बनाता है। – lashleigh

0

मैं निम्नलिखित के साथ जाना होगा:

import Data.Char 

caesar :: Int -> Char -> Char 
caesar n c = if isAlpha c 
      then chr (ord 'a' + (ord c - ord 'a' + n) `mod` 26) 
      else c 

और n के साथ स्ट्रिंग वांछित ऑफसेट से अधिक map (caesar n)

+0

यदि आप सवाल पढ़ते हैं, तो मुझे लगता है कि आपको अपना जवाब मिल जाएगा, जबकि चालाक, वास्तव में पूछे जाने वाले प्रश्न लशलेघ के लिए कुछ हद तक स्पर्शपूर्ण है। – Benson

संबंधित मुद्दे