VirtualProdigy
VirtualProdigy

Reputation: 1687

Haskell Convert a Maybe to a defined Type

I'm in my first few days of learning Haskell and I'm struggle with the Maybe type that is being returned from the Haskell's find function. I defined a function called FindNextState which takes in a tuple, and 2 Strings. This funcition calls getListOfNextStates which uses a lambda and pattern matching to get a list from the passed in tuple and then uses the find function's predicate I find a match in that list. The problem is find returns return a Maybe of my Transition type, this is preventing me from calling my getToState function because it's expecting at Transition. Is there anyway to convert the Maybe returned by find function?

Code

type State = String
type Symbol = String
type Transisition = (State, Symbol, State)

states = ["s0","s1"]
initState = "s0"
finalStates = ["s3"]
transisitionList = [("s0", "0", "s1"), ("s0", "1", "s1")]
dfa = (states, initState, finalStates, transisitionList)

getToState :: Transisition -> State
getToState  (_, _, toState) = toState


findNextState :: DFA -> State -> Symbol -> Maybe Transisition --Maybe Transisition is the issue, I need it to be my type of Transisition otherwise Haskell throws an error when I load my program 
findNextState (_,_,_,tList) state symbol =  getListOfNextStates tList state symbol

getListOfNextStates :: [Transisition] -> State -> Symbol -> Maybe Transisition
getListOfNextStates tList state symbol = find(\(sState,sym,eState) -> matchTransition state symbol (sState,sym,eState)) tList

Sample Input

findNextState dfa "s2" "0"
Just ("s2","0","s3")

*Main> :t findNextState dfa "s2" "0"
findNextState dfa "s2" "0" :: Maybe Transisition

** Desired Code**

findNextState :: DFA -> State -> Symbol -> State
findNextState (_,_,_,tList) state symbol = getToState( (getListOfNextStates tList state symbol) )

Upvotes: 1

Views: 2942

Answers (1)

DarthFennec
DarthFennec

Reputation: 2778

I'd recommend keeping the Maybe, as it allows the code to fail gracefully if it doesn't find a match. If you do that, you'll leave getListOfNextStates returning Maybe Transition, and then change findNextState to return Maybe State. Now you can define it like this:

findNextState :: DFA -> State -> Symbol -> Maybe State
findNextState (_,_,_,tList) state symbol = case newstate of
    Just s -> Just (getToState s)
    Nothing -> Nothing
  where newstate = getListOfNextStates tList state symbol

Or more succinctly, you can use fmap :: (a -> b) -> Maybe a -> Maybe b (or its infix version, <$>) like so:

findNextState :: DFA -> State -> Symbol -> Maybe State
findNextState (_,_,_,tList) state symbol = getToState <$> newstate
  where newstate = getListOfNextStates tList state symbol

If you really don't think there will be a failed find, or you just don't care, you can use fromJust :: Maybe Transition -> Transition, like so:

import Data.Maybe

getListOfNextStates :: [Transisition] -> State -> Symbol -> Transisition
getListOfNextStates tList state symbol = fromJust (find (\(sState,sym,eState) -> matchTransition state symbol (sState,sym,eState)) tList)

This will throw an exception if getListOfNextStates returns Nothing, effectively crashing the program. I wouldn't do this in real code unless you can absolutely ensure that it will never happen.

Upvotes: 6

Related Questions