Home > Blockchain >  How do I get the parameters out of the Maybe wrapper correctly?
How do I get the parameters out of the Maybe wrapper correctly?

Time:01-28

I want to get the Maybe parameters out of the Maybe wrapper

A wrapper that contains one or more approximation results

data CalculatedPoints =
    Linear {xPoints :: [Maybe Double], yPoints :: [Maybe Double] }
    | Segment {xPoints :: [Maybe Double], yPoints :: [Maybe Double]}
    deriving Show

Trying to get values

main = do
  resultPoints <- parseInput
  case resultPoints of
    [Nothing, Nothing] -> putStrLn "Calculation failed. Perhaps you did not specify a method."
    [lpoints, Nothing] -> do
      putStrLn "Linear Aproxiation"
      let (xl, yl) = fromMaybe (Nothing, Nothing) lpoints -- THIS
--      prettyPoints xl yl
      print $ xl
    [Nothing, spoints] -> do
      putStrLn "Segment Aproxiation"
      print spoints
    [lpoints, spoints] -> do
      putStrLn "Linear Aproxiation"
      print lpoints
      putStrLn "Segment Aproxiation"
      print spoints

I get this error

warning: [-Wdeferred-type-errors] 
    • Couldn't match type ‘CalculatedPoints’ with ‘(Maybe a, Maybe a1)
       Expected: Maybe (Maybe a, Maybe a1)         Actual: Maybe CalculatedPoints     • In the second argument of ‘fromMaybe’, namely ‘lpoints’ 
      In the expression: fromMaybe (Nothing, Nothing) lpoints       In a pattern binding:
         (xl, yl) = fromMaybe (Nothing, Nothing) lpoint

P.S I decided that parseInput was important for the context, so it turns out that calculatePoints is also necessary, so I included them

calculatePoints :: Interval -> Double -> Points -> Bool -> Bool -> [Maybe CalculatedPoints]
calculatePoints interval step points True True =
  [ Just (linearApproximation interval step points),
    Just (segmentApproximation interval step points)
  ]
calculatePoints interval step points True False = [Just (linearApproximation interval step points), Nothing]
calculatePoints interval step points False True = [Nothing, Just (segmentApproximation interval step points)]
calculatePoints _ _ _ False False = [Nothing, Nothing]


parseInput :: IO [Maybe CalculatedPoints]
parseInput = do
  input <- cmdArgs inputOptions
  points <- case file input of
                  "" -> getPointsNoFile []
                  path -> getPointsFile path
           
  return $ calculatePoints (left input, right input) 0.95 points (lm input) (sm input) 

CodePudding user response:

Notice that fromMaybe needs a default value of the same type. Below, your code commented with the mistake

main = do
  resultPoints <- parseInput -- This has type [Maybe CalculatedPoints]
  case resultPoints of
    -- This is the case where input is a list with two Nothing's . Looks good :)
    [Nothing, Nothing] -> putStrLn "Calculation failed. Perhaps you did not specify a method."
    -- This case is missleading. First, You can match directly (Just calcpoints)
    -- because the case where lpoints is Nothing, has being match before.
    -- so there is no need to have an irrefutable pattern (i.e. a variable ignoring the shape)
    -- Nevertheless, the error is below, not here
    [lpoints, Nothing] -> do
      putStrLn "Linear Aproxiation"
      --             |- This has type a -> Maybe a -> a (sumary: you provide a default value for Nothing, otherwise extract whatever is within Just)
      --             |          |- The default value has type "(Maybe a, Maybe a)" => a tuple of maybes
      --             |          |                 |- This has value (Maybe CalculatedPoints)
      let (xl, yl) = fromMaybe (Nothing, Nothing) lpoints -- THIS
      --  |- Also this has type tuple of maybes. Therefore GHC is complaining
      --     "you want me to extract a tuple but the value you provide is Maybe CalculatedPoints
      --      How in the heck I get a tuple from that??"
      prettyPoints xl yl
      print $ xl
.
.
.

Now, If you want to type check your code, It should be something like below. Notice that It isn't a very good / idiomatic haskell code.

main = do
  resultPoints <- parseInput
  case resultPoints of
    [Nothing, Nothing] -> putStrLn "Calculation failed. Perhaps you did not specify a method."
    [lpoints, Nothing] -> do
      putStrLn "Linear Aproxiation"
      --                      |- Provide a default value of the same type as the lpoints has "inside" the Just
      let points = fromMaybe (Linear [] []) lpoints
      --  |- not sure about this... But you can work it out 
      prettyPoints points??
      print $ xl

Now, If you want more idiomatic code I'd suggest

main = do
  resultPoints <- parseInput
  case resultPoints of
    [Nothing, Nothing] -> putStrLn "Calculation failed. Perhaps you did not specify a method."
    [Just (Linear xl yl), Nothing] -> do
      putStrLn "Linear Aproxiation"
      prettyPoints xl yl
      print $ xl
.
.
.

CodePudding user response:

I think I'd just delete most of this code. Here's a much simpler main with the same behavior:

main = do
  input <- cmdArgs inputOptions
  points <- case file input of
                  "" -> getPointsNoFile []
                  path -> getPointsFile path
  let interval = (left input, right input)

  unless (lm input || sm input) (putStrLn "Calculation failed. Perhaps you did not specify a method.")
  when (lm input) $ do
      putStrLn "Linear Aproxiation" -- sic
      print (linearApproximation interval 0.95 points)
  when (sm input) $ do
      putStrLn "Segment Aproxiation"
      print (segmentApproximation interval 0.95 points)

No Maybe needed; no CalculatedPoints needed (...probably. unless linearApproximation and segmentApproximation are weirder than their names sound); no fragile guaranteed-length-two list needed; and less code repetition between cases. There is still a little bit of repetition between the linear and segment printing code; if you really want, you could abstract those a little bit.

data ApproximationMethod = AM
    { name :: String
    , approx :: Interval -> Double -> Points -> Points
    , active :: InputOptions -> Bool
    }

allMethods :: [ApproximationMethod]
allMethods = [AM "Linear" linearApproximation lm, AM "Segment" segmentApproximation sm]

main = do
    {- ... -}
    for_ approximationMethods $ \am -> when (active am input) $ do
        putStrLn $ name am    " Aproxiation"
        print (approx am interval 0.95 points)

But for this little repeated code, that seems like overkill.

  • Related