[英]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: 将地图表示为函数作为第一近似是好的,但是这种表示具有许多缺点:
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. 为了清楚起见,我在这里使用了k
和v
代表“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 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
. 所以在这里你看到你可以返回dict
因为类型匹配,但这会忽略key
和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: 既然你知道Dict kv
是一个函数类型,你可以通过添加一个带有另一个洞的lambda来查看编译器提供的内容:
insertDict key value dict
= \ key' -> _
Now we have _ :: Maybe v
, value :: v
, key' :: k
, key' :: k
, dict :: Dict kv
. 现在我们有_ :: 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! 我们总是可以返回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 ==
: 我们可以比较的唯一两件事是key
和key'
,所以让我们将其扩展为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.