改进Has​​kell八位字节转换代码

时间:2013-09-14 16:42:26

标签: haskell type-conversion byte

我正在实现一些加密函数,因此,为了节省一些时间,我编写了一个模块,用于在Word8[Octet]ByteString之间转换八位字节(UArray Int Octet) 。如何改进我的代码?我确信现有的Haskell模块包含的函数会缩短我的代码。我通过hlint运行了它。

{-# LANGUAGE FlexibleInstances #-}

module Octets where

import Codec.Utils (Octet)
import Data.Array.IArray (elems, listArray)
import Data.Array.Unboxed (UArray)
import qualified Data.ByteString as B (ByteString, length, pack, unpack)

class FromByteString a where
  fromByteString :: B.ByteString -> a

instance FromByteString [Octet] where
  fromByteString = B.unpack

instance FromByteString (UArray Int Octet) where
  fromByteString bytes = listArray (0, B.length bytes - 1) $ B.unpack bytes

class FromOctets a where
  fromOctets :: [Octet] -> a

instance FromOctets B.ByteString where
  fromOctets = B.pack

instance FromOctets (UArray Int Octet) where
  fromOctets bytes = listArray (0, length bytes - 1) bytes

class FromUArray a where
  fromUArray :: UArray Int Octet -> a

instance FromUArray B.ByteString where
  fromUArray = B.pack . elems

instance FromUArray [Octet] where
  fromUArray = elems

以下是测试套件:

{-# LANGUAGE OverloadedStrings #-}

module OctetsSpec where

import Codec.Utils (Octet)
import Data.Array.IArray (listArray)
import Data.Array.Unboxed (UArray)
import qualified Data.ByteString as B (ByteString, length, unpack)
import Octets
import Test.Hspec (describe, hspec, it, shouldBe, Spec)

main :: IO ()
main = hspec spec

spec :: Spec
spec = specOctets

specOctets :: Spec
specOctets = do
  describe "FromByteString" $ do
    it "should convert ByteString to [Octet]" $ do
      let result = fromByteString "foobar" :: [Octet]
      result `shouldBe` [102, 111, 111, 98, 97, 114]

    it "should convert ByteString to (UArray Int Octet)" $ do
      let testString = "foobar"
          result = fromByteString testString :: UArray Int Octet
      result `shouldBe`
        (listArray (0, B.length testString - 1) $ B.unpack testString)

  describe "FromOctets" $ do
    it "should convert [Octet] to ByteString" $ do
      let result = fromOctets [102, 111, 111, 98, 97, 114] :: B.ByteString
      result `shouldBe` "foobar"

    it "should convert [Octet] to (UArray Int Octet)" $ do
      let testList = [102, 111, 111, 98, 97, 114]
          result = fromOctets testList :: (UArray Int Octet)
      result `shouldBe` (listArray (0, length testList - 1) testList)

  describe "FromUArray" $ do
    it "should convert (UArray Int Octet) to ByteString" $ do
      let testList = [102, 111, 111, 98, 97, 114]
          result = (fromUArray $
            listArray (0, length testList - 1) testList) :: B.ByteString
      result `shouldBe` "foobar"

    it "should convert (UArray Int Octet) to [Octet]" $ do
      let testList = [102, 111, 111, 98, 97, 114]
          result = (fromUArray $
            listArray (0, length testList - 1) testList) :: [Octet]
      result `shouldBe` testList

1 个答案:

答案 0 :(得分:2)

这是lens提供Iso类型的3 choose 2 = 3最喜欢的用途之一。由于你有3个例子,你可以用byteStringOctets :: Iso' ByteString [Octet] uarrayOctets :: Iso' (UArray Int Octet) [Octet] byteStringUArray :: Iso' ByteString (UArray Int Octet) 同构来说明它们都是彼此同构的。

Iso'

由于这些很常见vector,它们也已经存在。特别是如果您愿意使用array包而不是byteStringOctets = from packedBytes -- from Data.ByteString.Lens -- works with lazy and strict ByteStrings vectorOctets :: Iso' (Vector Octet) [Octet] vectorOctets = from vector -- from Data.Vector.Lens byteStringVector :: Iso' ByteString Vector

byteStringVector

其中{{1}}可以通过将这些当前同构点粘合在一起(低效)或通过限制类型并进行直接转换as this Stack Overflow question describes来实现。