Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
派生Haskell类型和(<;*>;)(<;*>;)的实现_Haskell_Types_Functional Programming - Fatal编程技术网

派生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