2

I am student and in my programming course we have to learn Haskell. So I am new to it and i don't have that much experience. Also I am not familiar with posting questions in a forum.

So first of all I will post the library, I have to work with. (DA : Deterministic Automaton)

type State = Integer
type DA = (State, State -> Char -> State, State -> Bool)
type ListDA = (State, [((State, Char), State)], [State])

a :: DA
a = (0, delta, (==1))
  where
    delta 0 'a' = 1
    delta 1 'a' = 1
    delta 2 'a' = 1
    delta 0 'b' = 2
    delta 1 'b' = 2
    delta 2 'b' = 2

toDA :: ListDA -> DA
toDA (start, delta, final) = (start, deltaFun delta, (`elem` final))
  where deltaFun dl = curry (fromMaybe 0 . flip lookup dl)  

The toDA function takes an automaton in its list representation and converts it into an automaton. This function and the rest of the library is given by the chair of the lecture.

The problem is now to write a function of type

advance :: DA -> State -> String -> State

This function takes an automaton, a state and a String and returns the state of the automaton after reading the String.

The Idea is clear so far. An automaton of type DA has got a state-transition-function delta. So the function "advance" has to call that delta function in some way. But how can I access a function, that is integrated in a type?

Cœur
  • 37,241
  • 25
  • 195
  • 267
0niveau
  • 23
  • 3

2 Answers2

4

You use pattern matching for that:

advance :: DA -> State -> String -> State
advance (start, step, accept) fromState chars = ....

The type keyword just introduces type synonyms. DA is just a synonym for a triple (Integer, Integer -> Char -> Integer, Integer -> Bool).

Your naming is confusing. delta in the definition of a automaton is a state transition function, but in the definition of toDA function, a parameter named delta is a list. ListDA type is also just a synonym for a triple (a different one - of a state, a list of transitions, and a list of acceptable states).

Here is how this can be coded, using recursion for loops:

advance (_, step, _) fromState chars = go fromState chars
  where
    go s []     = ...  -- stop, and produce the state as the answer,
                       -- when the input string (list of chars) has ended
    go s (c:cs) =         -- if not, then
      let s2 = step s c   -- make one step
      in  go .......      -- and loop with new values

Notice we have no need here for the start or accept variables, so we can use the anonymous variable pattern _ there. Also, step is a function of type State -> Char -> State, and that dictates the order of arguments used in the function call there. I.e. it accepts a state and a character, and produces a new state.

If you don't know Haskell at all, you will likely benefit from reading (and working through) a good tutorial, like this one.

Lastly, since you've said you're "not familiar with posting questions in a forum", please read about accepting answers, and FAQ in general.

Community
  • 1
  • 1
Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • thanks for your fast support. I've tried to work out a solution, but without success. I've tried 'advance :: DA -> State -> String -> State advance (start, step, accept) State Char:Chars = advance (start, step, accept) (step State Char) Chars ' I aimed to implement a recursive functions to cycle through the elements of the String to be read. Loading it into GHCi produces a parse error. So where is my mistake? – 0niveau Nov 20 '12 at 13:39
  • @user1838559: Variables have to begin with a lower case letter, so use `chars` not `Chars`. Also, operators like `:` have lower precedence than function application, even in patterns, so you need to put parentheses around `(char:chars)`. – hammar Nov 20 '12 at 13:44
  • @hammer: Thank You for that answer. I apologize for asking such a stupid question and for wasting your time with these spelling-mistakes ;-) – 0niveau Nov 20 '12 at 13:50
  • @user1838559 what should happen if we hit an accepting state mid-string? Should we continue trying to read from the input string until it is exhausted, or can we stop at this point? – Will Ness Nov 20 '12 at 14:46
  • @WillNess: the whole input-String has to be read, although an accepted state might be hit during the process. I now have solved the problem thanks to your answer, but I've got another aspect you could help me with. This is my advance-function:
    `advance :: DA -> State -> String -> State` `advance (start, step, final) state [] = state` `advance (start, step, final) state (char:chars) = advance (start, step, final) (step state char) chars` is it possible to write (start, step, final) just once by using a 'where' statement and replacing the other triples by somethingt like 'Automaton' ?
    – 0niveau Nov 20 '12 at 19:54
  • @0niveau this is done with at-patterns (@): `advance _ state [] = state ; advance da@(_, step, _) state (char:chars) = advance da (step state char) chars`. BTW this is also equivalent to `advance (_, step, _) s str = foldl step s str`. Or even just `advance (_, step, _) = foldl step`. – Will Ness Nov 21 '12 at 07:33
3

Functions aren't actually any different from any other type of data in Haskell, until you evaluate them – at which point there isn't any difference between a globally defined function, a function variable obtained by pattern matching, or an unnamed lambda.

In this case, as Will Ness said, it's easiest to obtain the function by pattern matching on a name,

advance (start, delta, terminate) = result

then you can, in this scope, use delta and terminate like any other function:

 where result = delta start 'b'  -- or whatever, conditional on terminate...
leftaroundabout
  • 117,950
  • 5
  • 174
  • 319