Du må være registrert og logget inn for å kunne legge ut innlegg på freak.no
X
LOGG INN
... eller du kan registrere deg nå
Dette nettstedet er avhengig av annonseinntekter for å holde driften og videre utvikling igang. Vi liker ikke reklame heller, men alternativene er ikke mange. Vær snill å vurder å slå av annonseblokkering, eller å abonnere på en reklamefri utgave av nettstedet.
  14 1165
For dem som likte Den Universelle Serveren (forum-link); nå har jeg laget en video til. Her implementerer jeg en stack-basert kalkulator.

Det er fortsatt ingen voice-over, men koden er enklere å følge, og blogposten har også endel kommentarer man kan lese først som en forberedelse.
Sikkerhet/Utvikling
CodeBarbarian's Avatar
Dette var utrolig interesangt! Har tatt meg tid og sett igjennom en del nå!

Dette falt jammen i smak ja!
Interessant.

Jeg prøver fra tid til annen å forstå LISP, så de videoene dine er midt i blink!
Fortsett gjerne med det
Likte denne veldig godt. God ide å forklare noe av syntaxen i teksten først! Liker både denne og den om universell server. Kunne kanskje vært forklart litt hva du vil oppnå og bruk for koden, men det dekkes fint i selve videoen. Hvertfall i den om en universell server, så er det innimellom litt vanskelig å følge med, men det er kanskje derfor du forer med en litt finere skje i denne. Godt jobbet!
Fin video av en Stack-basert kalkulator tormaroe.
Dette så ut som en artig oppgave,så lagde en versjon i python.
Testet litt og gjort noe feilbehandling,fulgte ikke et TDD opplegg under denne oppgaven.

Kode

class Stack_calc(object):
    '''Stack calulator - push numbers into stack - calculate last 2 elements'''
    def __init__(self):
        self.item = []
        self.calculate =\
         {'+' : lambda: self.item.append(self.item.pop() + self.item.pop()),
          '-' : lambda: self.item.append(self.item.pop() - self.item.pop()),
          '*' : lambda: self.item.append(self.item.pop() * self.item.pop()),
          '/' : lambda: self.item.append(self.item.pop() / self.item.pop()),}

    def parse_stack(self, source):
        stack = source.split()
        for element in stack:
            try:
                self.item.append(float(element))
            except ValueError:
                if element in self.calculate:
                    try:
                        self.calculate[element]()
                    except IndexError:
                        pass

    def __str__(self):
        return str(self.item)

def main():
    obj = Stack_calc()
    #Enter number will add to stack,use operators +-*/ to calculate 2 last elements
    #To exit type Q
    while True:
        into_stack = raw_input(':-> ')
        if into_stack == 'Q':
            break
        obj.parse_stack("%s" % into_stack)
        print obj

if __name__ == '__main__':
    main()
Testkjøring.

Kode

>>> 
:-> 1
[1.0]
:-> 2
[1.0, 2.0]
:-> 3
[1.0, 2.0, 3.0]
:-> 4
[1.0, 2.0, 3.0, 4.0]
:-> 5
[1.0, 2.0, 3.0, 4.0, 5.0]
:-> +
[1.0, 2.0, 3.0, 9.0]
:-> -
[1.0, 2.0, 6.0]
:-> *
[1.0, 12.0]
:-> /
[12.0]
:-> /
[]
:-> 10000
[10000.0]
:-> 2222 44444
[10000.0, 2222.0, 44444.0]
:-> 5555
[10000.0, 2222.0, 44444.0, 5555.0]
:-> 900000000
[10000.0, 2222.0, 44444.0, 5555.0, 900000000.0]
:-> /
[10000.0, 2222.0, 44444.0, 162016.20162016203]
:-> *
[10000.0, 2222.0, 7200648064.806481]
:-> +
[10000.0, 7200650286.806481]
:-> -
[7200640286.806481]
:-> -
[]
:-> Q
>>>
codeslinger
tormaroe's Avatar
Trådstarter
Sitat av snippsat Vis innlegg
Dette så ut som en artig oppgave,så lagde en versjon i python.
Vis hele sitatet...
Kult. Du har ikke fulgt spekken helt ser det ut som - hvis du bare har ett tall på stacken, og du sender en operator, skal tallet erstatte begge operandene. Altså hvis stack = [1] gir operator + ny stack = [2].
Du har ikke fulgt spekken helt ser det ut som - hvis du bare har ett tall på stacken, og du sender en operator, skal tallet erstatte begge operandene. Altså hvis stack = [1] gir operator + ny stack = [2].
Vis hele sitatet...
Ja var nok klar over det,ble litt sent
Versjon 1 tømmer da stacken med gjenntagene operator.
Versjon 2 skal følge spekken din.

Kode

class Stack_calc(object):
    '''Stack calulator'''
    def __init__(self):
        self.item = []
        self.calculate =\
         {'+' : lambda: self.item.append(self.item.pop() + self.item.pop()),
          '-' : lambda: self.item.append(self.item.pop() - self.item.pop()),
          '*' : lambda: self.item.append(self.item.pop() * self.item.pop()),
          '/' : lambda: self.item.append(self.item.pop() / self.item.pop())}

    def parse_stack(self, source):
        self.stack = source.split()
        for num in self.stack:
            try:
                self.item.append(float(num))
            except ValueError:
                for element in self.stack:
                    if element in ['+','-','*','/'] and len(self.item) > 1:
                        self.calculate[element]()
                    else:
                        try:
                            d = {'+': self.item[0] + self.item[0],'-': self.item[0] - self.item[0],
                                 '*': self.item[0] * self.item[0],'/': self.item[0] / self.item[0]}
                            if element in d:
                                self.item[0] = d[element]
                        except (IndexError,ZeroDivisionError):
                            pass

    def __str__(self):
        return str(self.item)

def main():
    '''Enter numbers,will be added to a stack
    use operators +-*/ to calculate 2 last elements
    To exit type Q
    '''
    obj = Stack_calc()
    while True:
        into_stack = raw_input(':-> ')
        if into_stack == 'Q':
            break
        obj.parse_stack("%s" % into_stack)
        print obj

if __name__ == '__main__':
    main()
Testkjøring.

Kode

>>> 
:-> 1
[1.0]
:-> 2
[1.0, 2.0]
:-> 3
[1.0, 2.0, 3.0]
:-> 4
[1.0, 2.0, 3.0, 4.0]
:-> 5
[1.0, 2.0, 3.0, 4.0, 5.0]
:-> +
[1.0, 2.0, 3.0, 9.0]
:-> -
[1.0, 2.0, 6.0]
:-> *
[1.0, 12.0]
:-> /
[12.0]
:-> -
[0.0]
:-> 1
[0.0, 1.0]
:-> +
[1.0]
:-> +
[2.0]
:-> +
[4.0]
:-> *
[16.0]
:-> 1000
[16.0, 1000.0]
:-> 500.25 147 0.899
[16.0, 1000.0, 500.25, 147.0, 0.899]
:-> *
[16.0, 1000.0, 500.25, 132.153]
:-> *
[16.0, 1000.0, 66109.53825]
:-> /
[16.0, 66.10953825]
:-> /
[4.131846140625]
:-> -
[0.0]
:->
Sist endret av snippsat; 3. mai 2011 kl. 10:12.
codeslinger
tormaroe's Avatar
Trådstarter
Sitat av snippsat Vis innlegg
Versjon 2 skal følge spekken din.
Vis hele sitatet...
Har laget en gist med koden din - enklere å lese da!

Våger meg på å kommentere et par ting, selv om jeg ikke koder mye python:
  • Liker veldig godt hvordan du har laget en hashtabell (eller hva det nå heter i python) med mapping mellom operatorer og anonyme funksjoner. Fører til ren kode som er enkel å utvide.
  • Liker ikke at du konverterer string til float først, og bruker exception til å håndtere operatorer. Ikke god standard i de miljøene jeg er bevandret i alle fall.
  • I stedet for "if element in ['+','-','*','/']" burde du slå opp mot nøklene til self.calculate - hvis ikke må du vedlikeholde listen av operatorer to steder
  • Og til slutt, håndteringen av kun ett tall på stacken når man behandler en operator liker jeg ikke. Igjen dupliserer du informasjon om operatorene. Ville forsøkt å finne en metode hvor jeg A) ikke trenger å repetere hvordan operatoren fungere, og B) ikke trenger å repetere hvilke tall som skal brukes som parametre til operatoren.

Bare ment som tips til å skrive renere kode..
Sist endret av tormaroe; 3. mai 2011 kl. 13:33.
Jeg får lage noe som følger spesifikasjonen jeg og, da. (Den Reverse Polish Notation-greia på bloggen hans var meg .)

Python:

Kode

#!/usr/bin/env python3

ops = {'*': lambda x, y: x * y, '+': lambda x, y: x + y,
       '/': lambda x, y: x / y, '-': lambda x, y: x - y}
stack = []
while True:
    x = input(':-> ')
    if x in ops:
        if len(stack) == 1:
            stack.append(stack[0])
        stack.append(ops[x](stack.pop(), stack.pop()))
    else:
        try:
            stack.append(float(x))
        except ValueError:
            print("Invalid number or operator.")
    print(stack)
Haskell:

Kode

import System.IO (hFlush, stdout)
import Data.Maybe

ops = [("*", (*)), ("+", (+)), ("/", (/)), ("-", (-))]

handle x ys | isJust op = case ys of (y:y':ys') -> op' y' y : ys'
                                     (y:ys')    -> op' y y : ys'
                                     _          -> error "Empty stack."
            | otherwise = read x : ys
  where op  = lookup x ops
        op' = fromJust op

run st = do putStr ":-> "
            hFlush stdout
            x <- getLine
            let st' = handle x st
            print st'
            run st'

main = run []
codeslinger
tormaroe's Avatar
Trådstarter
Snippsat, ta en titt på python-versjonen til Akhharu - han har gjort de tingene jeg påpekte.

Og for en gangs skyld var Haskell-versjonen også nesten leselig
Ja er enig med dine vurderinger tormaroe,fine løsninger Akhkharu.
Prøvde meg på en c# versjon. Var egentlig mapping av anonyme funksjoner jeg ville prøve å få til, og det funket jo. Litt uvant stil for en som stort sett kan java og c#. Her er koden: http://pastebin.com/XUtswFv5
codeslinger
tormaroe's Avatar
Trådstarter
Sitat av lor3ntz Vis innlegg
Prøvde meg på en c# versjon. Var egentlig mapping av anonyme funksjoner jeg ville prøve å få til, og det funket jo. Litt uvant stil for en som stort sett kan java og c#. Her er koden: http://pastebin.com/XUtswFv5
Vis hele sitatet...
Ikke dum den.

Her er en utfordring siden du eksperimenterer med anonyme metoder: Kan du klare å endre koden slik at lambda-uttrykkene i calculate ikke har noen referanse til stacken? I stedet for Dictionary<Char, Action> kan det kanskje være en ide å bruke Dictionary<Char, Func<double, double, double>>
C++0x kommer for full fart og har lambda-funksjonalitet, så jeg tenkte jeg skulle prøve på en versjon i C++ for å få testet det ut. Har aldri brukt lambda-funksjoner før, men det var jo overraskende praktisk.

Koden er her, hvis noen vil se hvordan lambda-funksjoner i C++ ser ut: http://pastebin.com/DtuXHeHL
Sist endret av Provo; 5. mai 2011 kl. 11:59.
codeslinger
tormaroe's Avatar
Trådstarter
Sitat av Provo Vis innlegg
C++0x kommer for full fart og har lambda-funksjonalitet, så jeg tenkte jeg skulle prøve på en versjon i C++ for å få testet det ut. Har aldri brukt lambda-funksjoner før, men det var jo overraskende praktisk.
Vis hele sitatet...
Ganske ren og fin syntax.