2011-10-24 3 views
1

스택 관리 시스템을 개발하고 싶습니다. 목록은 비어있는 것으로 시작합니다 []. 사용자는 숫자를 입력 할 수 있고 목록에 추가되며 이진 연산은 목록에서 두 개의 첫 번째 숫자를 취하여 작업을 수행 한 다음 목록에 다시 추가합니다 . 예 :haskell : RPN 계산기

[] : 3 
[3] : 4 
[4,3] : + 
[7] : c 
[] : 123 
[123] : 3 
[3,123] : * 
[369] : 

콘솔에서 입력을 처리하는 방법을 알 수 없습니다. 나는이 깨진 코드를 가지고있다.

import System.Environment 
import System.Directory 
import System.IO 
import Data.List 

stack = [] 

add1 :: [Int] -> [Int] 
add1 [] = [] 
add1 [x] = [x] 
add1 [x,y] = [(x+y)] 
add1 x:(y:xs) = (x+y) : (xs : []) 

--sub :: [Int] -> [Int] 
--sub [] = [] 
--sub x:(y:xs) = (x-y) : xs 

--mul :: [Int] -> [Int] 
--mul [] = [] 
--mul x:(y:xs) = (x*y) : xs 

--div :: [Int] -> [Int] 
--div [] = [] 
--div x:(y:xs) = (x/y) : xs 

c :: [Int] -> [Int] 
c = [] 

push :: [Int] -> a -> [Int] 
push [] a = [a] 
push (x:xs) a = a : (x:xs) 

dispatch :: [(String, Int -> IO())] 
dispatch = [ ("+", add) 
     --  , ("-", sub) 
     --  , ("*", mul) 
     --  , ("/", div) 
      ] 

xcl = do 
    print stack 
    answer <- readLine 

그러나 나는 올바른 방향으로 가고 있는지조차 모른다. 어떤 도움이 될 것입니다. 고맙습니다. 우리가 그것을 조작 할 것이기 때문에

답변

4

은 올바른 경로에입니다. 제안 할 코드에 대한 몇 가지 변경 사항을 살펴 보겠습니다.

귀하의 add1 기능은 아주 가깝지만, 두 가지 작은 문제가 있습니다. 첫 번째는 제공 한 패턴 일치입니다. 구문이 정확하려면 전체 일치가 괄호 안에 있어야합니다. 두 번째는 두 번째 죄수 (콜론)입니다. cons는 a -> [a] -> [a] 유형이므로 첫 번째 매개 변수로 (x+y)과 완벽하게 작동합니다. 그러나 xs은 이미 [Int] 유형이므로 : []을 제공 할 필요가 없습니다.

add1 (x:y:xs) = (x+y) : xs 

다음,이 맥락에서 이해가되지 않습니다 어떤 종류의 a를 사용하여, Int들과 Int의 목록 전적으로 다루고 있기 때문이다.

push :: [Int] -> Int -> [Int] 

마지막으로, 귀하의 주력 기능. 하스켈에서 루프 구조가 부족하기 때문에 사용자 입력 루프 (REPL이라고도 함)를 수행하는 방법은 재귀를 통한 방법입니다. 이 때문에 매개 변수를 허용하는 것이 좋습니다. 너의 [Int] 스택을 만들자. stdin에서 한 행을 문자열로 읽는 함수는 getLine이고 유형은 IO String입니다. 마지막으로, 실제로 그 입력을 처리해야합니다. 단순화를 위해 case 진술을 xcl에 포함 시켰지만 dispatch 또는 유사한 기능을 사용하여 수행 할 수있었습니다. (실제로 RPN 계산 도구가 더 복잡해지면 이점이 있습니다.) 각 사례에 대한 조치는 수정 된 스택을 사용하여 xcl "루프"에 재귀해야합니다. 종료하면 그냥 종료해야합니다. return을 사용하는 것이 좋습니다.

xcl :: [Int] -> IO() 
xcl st = do 
    print st 
    answer <- getLine 
    case answer of 
     "q" -> return() 
     "c" -> xcl ([] ::[Int]) 
     "+" -> xcl $ add1 st 
     x -> xcl $ push st $ read x 

사실, 당신은 한 단계 더 나아가 걸릴 수도 예외으로부터 보호 - 사용자가 아닌 일부 기능, 숫자가 아닌 문자열을 통과 할 때 무슨 일이 일어날 것인가? 위의 코드는 "구문 분석 안 함"예외와 함께 실패합니다. 그 주위의 가장 좋은 방법은 this answer에서 논의 된 것처럼 read 대신 reads을 사용하는 것입니다.reads은 단일 항목이있는 목록, 즉 구문 분석 된 숫자와 나머지 문자열을 포함하는 튜플 또는 빈 목록 (읽기 실패를 나타냄)을 반환합니다. 예 :

 x -> case (reads x) of 
     [(num,_)] -> xcl $ push st num 
     _ -> xcl st 
+0

감사합니다. 나는 일할 수있는 프로그램을 가지고있다 :) – DustBunny

2
xcl stack = do 
    print stack 
    answer <- getLine 
    case lookup answer dispatch of 
     Just function -> -- we have a function, apply it to the top of the stack 
     Nothing -> -- if we have a number, parse it and push it onto the stack 
        -- if not, issue an error 
  1. stack는 일정 최고 수준이 될 수 없습니다. 그래서 우리는 xcl의 매개 변수로 대신 사용합니다.
  2. 텍스트 줄을 읽으려면 getLine을 사용하십시오. 연산자 이름이나 숫자로 해석할지 여부는 알 수 없기 때문에 텍스트 줄을 읽으십시오.