派生Haskell类型和(<;*>;)(<;*>;)的实现
我是一个新手,刚开始学习哈斯克尔,所以如果我问一些愚蠢的问题,请容忍我 最近,我在演示如何导出函数和表达式的类型和实现时遇到了一些问题(例如 & ) 我觉得答案非常鼓舞人心 一、 然后,试着为自己做一些练习,以确保我知道如何应用这些技巧 然后我自己想出了这个表达式:派生Haskell类型和(<;*>;)(<;*>;)的实现,haskell,types,functional-programming,Haskell,Types,Functional Programming,我是一个新手,刚开始学习哈斯克尔,所以如果我问一些愚蠢的问题,请容忍我 最近,我在演示如何导出函数和表达式的类型和实现时遇到了一些问题(例如 & ) 我觉得答案非常鼓舞人心 一、 然后,试着为自己做一些练习,以确保我知道如何应用这些技巧 然后我自己想出了这个表达式:(),我不知道怎么解 在GHCi中,它给出的类型签名为: (<*>)(<*>) :: Applicative f => (f (a -> b) -> f a) -> f (a -&g
()
,我不知道怎么解
在GHCi中,它给出的类型签名为:
(<*>)(<*>) :: Applicative f => (f (a -> b) -> f a) -> f (a -> b) -> f b
()::应用程序f=>(f(a->b)->f a)->f(a->b)->f b
但我的问题是,我该如何开始
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
()::应用程序f=>f(a->b)->f a->f b
并派生GHCi给出的类型签名
此外,基于类型签名,()=??
的实现将如何
我被卡住了,无法通过重新安排条款等技术来解决这个问题。我甚至不知道从哪里开始
有人能帮我一下吗
非常感谢
注**:表达式
()()
实际上没有特殊含义,它只是我随机想出的一个练习,所以我们有了这个函数
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
但是g(c->d)->gc->gd
是(>)(g(c->d))(gc->gd)
的一种语法糖。因此:
(->) (g (c -> d)) (g c -> g d) = f (a -> b)
两侧的类型构造函数和参数类型必须相等,因此:
(->) (g (c -> d)) = f
及
这意味着a=gc
和b=gd
现在我们可以看到第一个()
的返回值是
f a -> f b = ((->) (g (c -> d)) (g c)) -> ((->) (g (c -> d)) (g d))
= (g (c -> d) -> g c) -> (g (c -> d) -> g d)
这与模重命名变量相同
本例中棘手的部分是
(>)(g(c->d))
是可应用的(与任何其他(>)e
相同)。首先,让我们用两组不相交的类型变量写出()
的类型:
(<*>) :: (Applicative f) => f (a -> b) -> f a -> f b
(<*>) :: (Applicative g) => g (c -> d) -> g c -> g d
屈服
g ~ (f (a -> b) ->) or, ((->) (f (a -> b)) )
c ~ f a
d ~ f b
请注意,选择g
确实是一个应用函数:它是一个非新类型的读取器(f(a->b))
applicative
因此应用程序具有类型
g c -> g d
我们现在知道是这样的
(f (a -> b) -> f a) -> (f (a -> b) -> f b)
q、 急诊室
此外,基于类型签名,如何实现
()=??
会是什么
颠倒顺序更容易(首先找到实现,然后派生其类型)
函数的应用实例是
instance Applicative ((->) a) where
pure = const
(<*>) f g x = f x (g x)
由于g::f(a->b)->c和g:h::f a
h :: f (a -> b)
g :: f (a -> b) -> c
g h :: f a , c ~ f a (!)
由于h
具有类型f(a->b)
,h(无论什么::f a)
具有类型f b
总之:
h :: f (a -> b)
g :: f (a -> b) -> f a
h <*> g h :: f b
h::f(a->b)
g::f(a->b)->f a
h:fb
所以我们有
\g h -> h <*> g h :: (f (a -> b) -> f a) -> f (a -> b) -> f b
\gh->hgh::(f(a->b)->fa)->f(a->b)->fb
作为练习,将其缩小到函数,其中
只是一个S-组合器
Prelude> let s f g x = f x (g x)
Prelude> :t s s
s s :: ((t -> t1 -> t2) -> t -> t1) -> (t -> t1 -> t2) -> t -> t2
-- g2 g4 g2 g1
-- g3 g3
-- g5
-- g6
重要的是要知道类型中的箭头与右边关联,因此((t->t1->t2)->t->t1)
实际上是((t->t1->t2)->(t->t1))
,而(t->t1->t2)
就是(t->(t1->t2))
实施:
g6 g5 g3 t :: t2
g3 t t1 :: t2 -- need t1
g5 g3 t :: t1
g3 t (g5 g3 t) :: t2 -- so,
h f g x = g x (f g x)
所以,当我们有一个类型,这只是一个问题,连接电线,可以说,或把乐高积木在一起。我们尝试查看给定实体(参数)的哪些组合具有什么类型,如果它们有助于获得所需的输出类型(t2
,如上),则在进一步的组合中使用它们
同样地
Prelude Control.Applicative> :t (<*>) (<*>)
(<*>) (<*>) :: (Applicative f) =>
(f (a -> b) -> f a) -> f (a -> b) -> f b
-- f fg
Prelude Control.Applicative> :t let axa f fg = fg <*> f fg in axa
let axa f fg = fg <*> (f fg) in axa :: (Applicative f) =>
(f (a -> b) -> f a) -> f (a -> b) -> f b
Prelude Control.Applicative>:t()()
():(应用f)=>
(f(a->b)->f a)->f(a->b)->f b
--f fg
前奏曲控制。应用>:t让axa f fg=axa中的fg f fg
让axa中的axa f fg=fg(f fg):(应用程序f)=>
(f(a->b)->f a)->f(a->b)->f b
感谢您分享这个问题的另一条途径,这很鼓舞人心。同时,我想澄清你回答中的一点。您首先为applicative类选择实例((->)a),我不确定您如何总结并选择该实例作为开始。你能告诉我这件事吗?Thanks@gatek,简而言之,()
应用于()
,后者是一个函数,因此您可以选择一个与函数对应的实例,而无需任何注意。或者你可以阅读f(a->b)->f a->f b
作为(>)(f(a->b))(f a->f b)
。谢谢你的快速回复。我很感激。我希望我能在这里接受多个答案,因为我认为你已经展示了一个有趣的替代方案来解决我的问题。圣诞快乐太棒了,我从来没有想过((->)(f(a->b))的诀窍。Brilliant可以举一个使用它的例子吗?甚至可能是一个有用的案例?谢谢你的额外灵感,我在SO-on combinators的不同帖子上遇到过好几次,但我永远也学不会。是否有任何文章/博客/材料可以推荐学习组合器?(及其相关文章)情况良好。至于一本书,对我来说是这样。实际上,组合表示法比lambda表达式更容易操作,依我看,Haskell遵循了组合的风格谢谢你的指点,我要看看。我也喜欢你的组合方法,我也会努力学习。圣诞快乐。我要感谢你们所有人及时提供高质量的答案,所有答案都很棒,令人鼓舞,它们为我节省了时间。我真的很难只选择一个。我希望我能接受多个答案。
\g h -> h <*> g h :: (f (a -> b) -> f a) -> f (a -> b) -> f b
Prelude> let s f g x = f x (g x)
Prelude> :t s s
s s :: ((t -> t1 -> t2) -> t -> t1) -> (t -> t1 -> t2) -> t -> t2
-- g2 g4 g2 g1
-- g3 g3
-- g5
-- g6
g6 g5 g3 t :: t2
g3 t t1 :: t2 -- need t1
g5 g3 t :: t1
g3 t (g5 g3 t) :: t2 -- so,
h f g x = g x (f g x)
Prelude Control.Applicative> :t (<*>) (<*>)
(<*>) (<*>) :: (Applicative f) =>
(f (a -> b) -> f a) -> f (a -> b) -> f b
-- f fg
Prelude Control.Applicative> :t let axa f fg = fg <*> f fg in axa
let axa f fg = fg <*> (f fg) in axa :: (Applicative f) =>
(f (a -> b) -> f a) -> f (a -> b) -> f b