2013-05-21 30 views
6

Myślałem o używaniu Haskella do serwera gry, ale kiedy zacząłem kodować, znalazłem się w części, w której parsuję pakiety myśląc "Wow, to spowoduje wiele dopasowań wzorców" . Widząc liczbę meczów do wykonania jest wielu (idź tam, zaatakuj, zdobądź łup, otwórz i tak dalej).Skutecznie dopasowuję wiele wzorów w Haskell

Co mogę zrobić, to:

  1. Odbierz paczkę
  2. Przetwarza nagłówek pakietu w systemie szesnastkowym String (powiedzmy "02B5" na przykład)
  3. Get resztę danych z pakietu
  4. Dopasuj nagłówek w parseIO
  5. Wywołanie odpowiedniej funkcji z zawartością pakietu

Łatwo byłoby odwzorować ciąg -> metoda, ale metody mają różną ilość parametrów.

Pomyślałem o prostych dwóch sposobach dopasowywania wzorów pokazanych poniżej.

#1 
packetIO :: String -> IO() 
packetIO packet = 
    case packet of 
    "02B5" -> function1 
    "ADD5" -> function2 
    ... and so on 

#2 
packetIO :: String -> IO() 
packetIO "02B5" = function1 
packetIO "ADD5" = function2 
... and so on 

Zarówno patrząc na wydajność i styl kodowania, istnieje sposób, aby lepiej obsługiwać pakiety otrzymane od klienta?

Jeśli masz jakieś zasoby lub linki, których nie udało mi się znaleźć, proszę wskazać mi kierunek!

EDIT 130521:

Wygląda obu alternatywnych, wymienionych poniżej, są dobrym wyborem. Tylko czekam na odpowiedź na moje pytania w komentarzach przed wyborem, które było dla mnie najlepszym rozwiązaniem.

  1. Przechowywanie (ByteString -> Function) w strukturze mapy. O (log n)
  2. Konwersja ByteString na Word16 i dopasowanie do wzorca. O (log n) przez drzewa lub O (1) za pomocą tabel przeglądowych

EDIT 130521:

postanowiliśmy pójść na wzór pasujący z Word16 jak Philip JF powiedział. Oba są świetne alternatywy i gdy moje przypuszczenie jest zarówno to równie szybko, mapa może być szybciej, gdyż ja nie trzeba konwertować do Word16, druga opcja dała kod bardziej czytelnym dla mojego użytku:

packetIO 0x02B5 = function1 
packetIO 0xADD5 = function2 
etc 
+9

Brzmi bardziej jak zadanie dla 'mapy' (z' Data.Map', z ['containers'] (http://hackage.haskell.org/package/containers)) , z 'ByteString' (naprawdę nie lubię' String';)) jako typu klucza i ** typ funkcji handler'a jako typ wartości **. Jeśli masz małe pakiety o stałej długości, to typ z 'Data.Word' (jak' Word16') będzie wystarczający jako klucz. W takim przypadku możesz nawet użyć 'Data.IntMap' dla jeszcze lepszej wydajności. –

+0

@Rhymoid: Czy mógłbyś zmienić to w odpowiedź, abym mógł go przyjąć? –

+0

@Rhymoid: Otrzymane dane rzeczywiście są ByteString na początku. Ale czy mapowanie nie dałoby mi złożoności czasu O (log n), gdy wybory z tablicami wyszukiwania dostarczały O (1)? A jak będą reprezentowane klucze ByteString? Używanie "pakietu" ze wszystkimi wariantami podczas ładowania? – Plankt

Odpowiedz

14

Dlaczego nie analizować do numerów (Word16 w Data.Word?), A następnie wykonać dopasowanie z tym, zamiast korzystania z ciągów? Haskell obsługuje literały szesnastkowe ...

+0

Parsowanie wyniku w Word16, zgaduję, że to byłby sposób, aby to zrobić? 'wypuść pakiet = rozpakuj $ ByteString.take 2 otrzymane' ' let word = fromIntegral (pakiet 1) * 0x100 + fromIntegral (pakiet !! 0) :: Word16' Następnie pasuje do: 'packetIO 0x02B5 -> function1' – Plankt

+0

Dość dużo. Możesz również spróbować użyć 'zboża' lub' binarnego', co byłoby szczególnie korzystne, gdyby struktura była bardziej skomplikowana niż czytanie numerów poleceń. –

10

Obie twoje funkcje są równoważne. Kompilator odsyła drugi do pierwszego. Dopasowywanie wzorca to cukier syntaktyczny dla case.

case jest optymalny dla tego rodzaju rzeczy. Kompiluje się do stołu skoku, który jest O (1). Oznacza to, że oba wymienione rozwiązania są optymalne.

Jeśli chodzi o styl kodowania, oba style są idealnie idiomatyczne. Osobiście wolę case niż dopasowywanie wzorca, ale wiem, że wiele innych osób preferuje dopasowywanie wzorca dla funkcji najwyższego poziomu.

+4

Czy kompiluje się do tabeli skoku z "String" też? Wątpię. –

+0

@Rhymoid Oops, całkowicie to przegapiłem. Wtedy nie mam pojęcia, co 'ghc' ma w tym przypadku. –