Home > Software design >  Converting different types into string
Converting different types into string

Time:11-10

The goal is to build a program to report the transactions for a particular stock in a human-readable format. For example, for our test data set, the transactions on the stock VTI will be printed as:

Bought 100 units of VTI for 1104 pounds each on day 1

Bought 50 units of VTI for 1223 pounds each on day 5

Sold 150 units of VTI for 1240 pounds each on day 9

Here is the test transaction code:

type Transaction = (Char, Int, Int, String, Int) 

test_log :: [Transaction]
test_log = [('B', 100, 1104,  "VTI",  1),
            ('B', 200,   36, "ONEQ",  3),
            ('B',  50, 1223,  "VTI",  5),
            ('S', 150, 1240,  "VTI",  9),
            ('B', 100,  229, "IWRD", 10),
            ('S', 200,   32, "ONEQ", 11), 
            ('S', 100,  210, "IWRD", 12)
            ]

For this, I thought is would be best to split each section into slices where they can be concatenated at the end.

--Converting transaction to string

transaction_to_string :: Transaction -> String
transaction_to_string (action: units: stocks: price: day) = 
    let display = action    "Bought"
        slice1 = units    "of"
        slice2 = stocks    "for"
        slice3 = price    "on day"
        slice4 = day
    in
        slice1    slice2    slice3   slice4

The error I am receiving is this. It is giving a type error but I am unsure why due to the type function used at the top:

   • Couldn't match type ‘[Char]’ with ‘Char’
      Expected: [Char]
        Actual: [[Char]]
    • In the second argument of ‘(  )’, namely ‘slice4’
      In the second argument of ‘(  )’, namely ‘slice3    slice4’
      In the second argument of ‘(  )’, namely
        ‘slice2    slice3    slice4’
   |
   |         slice1    slice2    slice3    slice4

CodePudding user response:

A first attempt:

transaction_to_string :: Transaction -> String
transaction_to_string (action, units, stocks, price, day) = 
                   -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ tuple, not list
    let display = show action    "Bought" -- << convert non-strings using `show`
        slice1 = show units    "of"       -- <<
        slice2 = show stocks    "for"     -- <<
        slice3 = price    "on day"
        slice4 = show day                 -- <<
    in
        display    slice1    slice2    slice3    slice4

You could improve this by:

  • adding spaces in the right places

  • formatting the string better: the order of the concatenation seems a bit off (test it!)

  • properly handling display, perhaps using something like:

      let display | action == 'B' = "Bought"
                  | action == 'S' = "Sold"
                  | otherwise     = "Uhh.. what?"
    

CodePudding user response:

Assuming Transaction were not a type synonym, ideally you would make it an instance of Show. For instance, if we used a record type.

data Transaction = Transaction {
  action :: Char,
  units :: Int,
  stocks :: String,
  price :: Int,
  day :: Int
}

instance Show Transaction where
  show (Transaction {action=a, units=u, stocks=s, price=p, day=d}) = str
    where
      a' = case a of 
        'B' -> "Bought"
        'S' -> "Sold"
        _ -> "Unknown action"
      str = a'    " "    show u    " units of "    s    
            " at $"    show p    " on day "    show d 

Now:

Prelude> Transaction {action='B', units=100, stocks="FOO", price=56, day=7}
Bought 100 units of FOO at $56 on day 7
  • Related