简体   繁体   English

函数作为haskell中的类型

[英]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. 假设我想实现一个字典,当给出a和b时返回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. 您可以使用“责任链”模式:insert函数检查结果 Dict的参数是否与其自己的键匹配,否则它委托前一个作为参数接收的Dict

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: 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. 为了清楚起见,我在这里使用了kv代表“key”和“value”。 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 . 编译器(或GHCi)应该给你一个消息,如“Found hole: _ :: Dict kv [...]相关绑定包括: dict :: Dict kvvalue :: vkey :: k So here you see that you could just return dict because the type matches, but that would ignore key and value . 所以在这里你看到你可以返回dict因为类型匹配,但这会忽略keyvalue

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: 既然你知道Dict kv是一个函数类型,你可以通过添加一个带有另一个洞的lambda来查看编译器提供的内容:

insertDict key value dict
  = \ key' -> _

Now we have _ :: Maybe v , value :: v , key' :: k , key' :: k , dict :: Dict kv . 现在我们有_ :: Maybe vvalue :: vkey' :: kkey' :: kdict :: 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! 我们总是可以返回Just value ,但正如您所观察到的那样,这并不能达到我们想要的效果 - 它代表的是一个字典总是回答“是的,那个键在字典中,它的值是value ”,对于您询问的任何键! (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! 所以看起来我们不能只用这些来取得进展 - 但等等,我们也有一个Eq k约束! And the only two things we can compare are key and key' , so let's expand this into an if using == : 我们可以比较的唯一两件事是keykey' ,所以让我们将其扩展为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 . 现在编译器报告_1 :: Maybe v_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 : 所以对于_1我们可以写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' : 所以对于_2我们可以写dict key'

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

And we're done! 我们完成了! :D :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. 在Haskell中编写时,这种类型导向编程等式推理的组合非常有用,特别是对于具有有限数量的可能(理智)实现的多态函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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