简体   繁体   中英

Functions as types in haskell

I have confusion using types which are functions.

Let say I want to implement a dictionary, which when given a and b returns Maybe b.

type Dict a b = a->Maybe b

How can I implement an insertion function for this dictionary?

insertDict :: (Eq a) => a -> b -> (Dict a b)-> (Dict a b)

I have come up with the following thing

insertDict x y mydict = \a->Just y

but it is not correct and will discard the previous dictionary.

You can use a "chain of responsibility" pattern: the insert function checks if the argument to the result Dict matches with its own key, otherwise it delegates on the previous Dict which received as argument.

type Dict a b = a -> Maybe b

insertDict :: (Eq a) => a -> b -> Dict a b -> Dict a b
-- Note that the k' is the argument of the result dict function
insertDict k v dict k' = if k == k' then Just v else dict k'

emptyDict :: Dict a b
emptyDict _ = Nothing

Some examples in ghci:

Λ insertDict 'a' (1::Int) emptyDict $ 'a'
Just 1
Λ insertDict 'b' 2 (insertDict 'a' (1::Int) emptyDict) $ 'a'
Just 1
Λ insertDict 'b' 2 (insertDict 'a' (1::Int) emptyDict) $ 'x'
Nothing

Representing maps as functions is good as a first approximation, but this representation has a number of drawbacks:

  • The complexity of searching for a value is linear in the number of keys.
  • Functions are pretty "opaque", which means you can't inspect or serialize the map as you could do if you had used a data type .

Here's one method you can use to help write such functions yourself. First, write the type signature:

insertDict :: (Eq k) => k -> v -> Dict k v -> Dict k v

I've used k and v for “key” and “value” here for clarity. Next, start by writing the implementation as a hole :

insertDict key value dict
  = _

The compiler (or GHCi) should give you a message like “Found hole: _ :: Dict kv […] Relevant bindings include: dict :: Dict kv , value :: v , key :: k . So here you see that you could just return dict because the type matches, but that would ignore key and value .

Since you know that Dict kv is a function type, you can make progress by adding a lambda with another hole to see what the compiler offers:

insertDict key value dict
  = \ key' -> _

Now we have _ :: Maybe v , value :: v , key' :: k , key' :: k , dict :: Dict kv . We could always return Just value , but as you observed, that doesn't do what we want—it represents a dictionary that always answers “Yes, that key is in the dictionary and its value is value ” for any key you ask about! (That is a useful thing to be able to represent, it's just not the thing we're writing.)

So it doesn't look like we can make progress with just these—but wait, we also have an Eq k constraint! And the only two things we can compare are key and key' , so let's expand this into an if using == :

insertDict key value dict
  = \ key' -> if key == key' then _1 else _2

Now the compiler reports _1 :: Maybe v and _2 :: Maybe v . What should we return in each of these cases? Let's consider some examples of how this function is actually used—if you look up a key in a dictionary after inserting a key-value pair, you should of course find the value:

(insertDict key value dict) key == Just value
                                   ----------

So for _1 we can write Just value :

insertDict key value dict
  = \ key' -> if key == key' then Just value else _2
                                  ----------

If you look up a different key than the one you just inserted, then the most recently inserted key-value pair doesn't matter; it should look up the key further on in the dictionary:

(insertDict key value dict) key' == dict key'  -- If key /= key'
                                    ---------

So for _2 we can write dict key' :

insertDict key value dict
  = \ key' -> if key == key' then Just value else dict key'
                                                  ---------

And we're done! :D

This combination of type-directed programming and equational reasoning is very helpful when writing in Haskell, especially for polymorphic functions like this that have a limited number of possible (sane) implementations.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM