如何从类型签名实现功能?
我在 Haskell 中有以下两种类型签名:
foo :: (a -> (a,b)) -> a -> [b]
bar :: (a -> b) -> (a -> b -> c) -> a -> c
我想编写这两个函数的具体实现,但我真的很难理解从哪里开始。
我知道它foo
需要一个函数(a -> (a,b))
并返回a
一个包含b
.
并bar
接受一个函数(b -> c)
,该函数返回一个(a -> b -> c)
最终返回a
和的函数c
。
谁能告诉我一个具体实现的例子?
我怎么知道从哪里开始这样的事情以及定义的左侧是什么?
回答
你有一些误解:
我知道它
foo
需要一个函数(a -> (a,b))
并返回a
一个包含b
.
不,它不会返回a
。除了那个函数之外,它还期望它是另一个参数。
并
bar
接受一个函数(b -> c)
,该函数返回一个(a -> b -> c)
最终返回a
和的函数c
。
同样在这里。给定g :: a -> b
,bar
返回一个函数bar g :: (a -> b -> c) -> a -> c
。这个函数反过来,给定一个函数h :: (a -> b -> c)
,返回一个类型为 的函数a -> c
。就这样了。
这就像玩拼图:
foo :: (a -> (a,b)) -> a -> [b]
-- g :: a -> (a,b)
-- x :: a
-- g x :: (a,b)
foo g x = [b] where
(a,b) = g x
bar :: (a -> b) -> (a -> b -> c) -> a -> c
-- g :: a -> b
-- x :: a
-- g x :: b
-- h :: a -> b -> c
-- h x :: b -> c
-- h x (g x) :: c
bar g h x = c where
c = ....
我们这里没有太多的自由选择。虽然,有更多方法可以获取更多类型的值b
,例如foo
。相反,忽视了的a
中(a,b) = g x
,我们可以在更多的应用程序使用它g
,所以其实有很多可能性在那里,就像
foo2 :: (a -> (a,b)) -> a -> [b]
foo2 g x = [b1,b2] where
(a1,b1) = g x
(a2,b2) = g a1
还有很多。尽管如此,类型仍指导可能的实现。根据类型,foo
甚至可以foo
在其实现中使用:
foo3 :: (a -> (a,b)) -> a -> [b]
foo3 g x = b : bs where
(a,b) = g x
bs = ...
所以现在,有了这个实现,前两个变成了它的特例:foo g x === take 1 (foo3 g x)
和foo2 g x === take 2 (foo3 g x)
. 拥有最一般的定义可能是最好的。