MathCoolGuy99
MathCoolGuy99

Reputation: 13

Replacing Strings with a List of Tuples of Strings

I want to write a function called trained that takes a string replacement function and a list of word pairs (two-tuples of strings).

I have tried using map and lambda function but still getting some error. Any help on this problem would be much appreciated!

Function train should have this type of signature: train :: Eq a => (a -> t) -> [(a, t)] -> a -> t

Here is some error:

Couldn't match expected type [Char] -> b'
with the actual type [[Char] -> [Char]]

Here is my code:

extend repl old new = \str -> if (str == old) then new 
                              else if (str == new) then old 
                              else (repl str)

train fn lst =  map (\(a,b) -> extend fn a b) lst

The function train should work out like this:

In: let improved = train (\s->s) [("kittens","puppies"),
                      ("tea","coffee"),("Java","Haskell")]

In: map improved ["my","favorite","things","are",
                      "kittens","Java","tea","and","rainbows"]

Out: ["my","favorite","things","are","puppies","Haskell","coffee","and","rainbows"]

Upvotes: 1

Views: 213

Answers (1)

You're trying to call map improved, but the first argument to map has to be a function, and :t improved shows you that improved is actually a list of functions: improved :: [[Char] -> [Char]]. The problem is that train is returning a list of functions, rather than a single composed function. To fix that, change map (\(a,b) -> extend fn a b) to foldr (\(a,b) f -> extend f a b) fn.

Also, your code is a bit unidiomatic and complex. Here's how I'd write it:

extend :: Eq a => (a, a) -> (a -> a) -> a -> a
extend (old, new) repl str
  | str == old = new
  | str == new = old
  | otherwise = repl str

train :: Eq a => (a -> a) -> [(a, a)] -> a -> a
train = foldr extend

improved :: String -> String
improved = train id [("kittens","puppies"),("tea","coffee"),("Java","Haskell")]

Now that you edited your question to include a required type signature, there's a change you have to make: extend must only do its replacement unidirectionally (i.e., it can't test for str == new and replace it with old). Here's how it would look idiomatically after that:

extend :: Eq a => (a, t) -> (a -> t) -> a -> t
extend (old, new) repl str
  | str == old = new
  | otherwise = repl str

train :: Eq a => (a -> t) -> [(a, t)] -> a -> t
train = foldr extend

improved :: String -> String
improved = train id [("kittens","puppies"),("tea","coffee"),("Java","Haskell")]

Upvotes: 3

Related Questions