【问题标题】:haskell function type simplifyed f :: ((b -> a ) -> a -> c ) -> (b -> a ) -> b -> c [closed]haskell 函数类型简化 f :: ((b -> a ) -> a -> c ) -> (b -> a ) -> b -> c [关闭]
【发布时间】:2020-12-25 00:16:16
【问题描述】:

只是找这个函数的类型的解释,拜托

f x y z = x y (y z)

前奏说是

f :: ((b -> a) -> a -> c) -> (b -> a) -> b -> c

但我无法使用任何已知方法获得该结果 ¬¬

最好的问候。

【问题讨论】:

  • 这是一道作业题吗?您能向我们展示您到目前为止所做的尝试吗?
  • “前奏曲”你可能是指Prelude> ?
  • NB f :: ((b -> a) -> a -> c) -> (b -> a) -> b -> c == f :: ((b -> a) -> (a -> c)) -> (b -> a) -> (b -> c)。因此f ba_ac ba = ba >>> (ba & ba_ac) :: {ba >>> ac} :: bc,如@leftaroundabout的答案所示。

标签: haskell types functional-programming logic declarative


【解决方案1】:

来自f x y z = x y (y z),你可以这样推理:

  • 我们不会将z 应用于任何东西,所以它可以有一些任意类型;称它为u1(对于未知的第一名)。

  • y应用于z,所以它的参数类型是u1,但是返回类型是另一个未知类型u2。因此y :: u1 -> u2

  • y z 因此具有类型u2

  • x 应用于y y z,因此必须具有类似(u1 -> u2) -> u2 -> u3 的类型;没有理由假设任一参数具有相同的类型,或者任一类型与返回类型相同。

  • f的返回值与x的返回值相同,即u3

总而言之,我们有

f :: ((u1 -> u2) -> u2 -> u3) -> (u1 -> u2) -> u1          ->    u3
     ------------------------    ----------    --                --
         type of x                type of y    type of z        end result of f

因为各个类型变量的名称除了保持不同的类型分开之外并不重要,我们可以使用重命名它们

  • u1 ~ b
  • u2 ~ a
  • u3 ~ c

获取您查找的类型

f :: ((b  -> a) -> a  -> c) -> (b  -> a) -> b  -> c

【讨论】:

    【解决方案2】:

    呃,那些“手动检查这个表达式”的练习太傻了。我不知道为什么讲师总是把他们放在作业中。

    在实践中,实际上更相关的是反过来:给定一个类型,找到一个实现。那么让我从这个角度回答这个问题:你已经知道了

    f :: ((b -> a) -> a -> c) -> (b -> a) -> b -> c
    --   └──────────────────┘    └──────┘   └─┘
    

    ...所以你要接受三个参数,足够合理地称它们为xyz

    f x y z = _
    

    你最终在寻找c,而你唯一可用的cx的最终结果中

        x :: (b -> a) -> a -> c
        --   └──────┘   └─┘
    

    ...需要两个参数

    f x y z = x _ _
    

    ...b -> aa 类型。让我们检查一下我们有什么可用的

        y :: b -> a
        z :: b
    

    太好了,我们可以直接使用y作为第一个参数

    f x y z = x y _
    

    对于第二个参数,我们需要一个a。好吧,zb,这不起作用,但是当给定 b 时,y 会产生 a,所以我们可以通过 y z 并最终得到

    f x y z = x y (y z)
    

    或者我们更喜欢用 Haskell 编写它,f x y = x y . y

    现在反过来:让我们从 η 约简形式开始

    f x y = x y . y
    

    这是一个管道,所以让我们开始为传递参数命名p

            x y . y :: p -> _
    

    该参数首先传递给y,所以我们有

            y :: p -> _
    

    由此而来,因为y 也是x 的第一个参数

            x :: (p -> _) -> _
    

    此外,x 然后接受(在管道中)来自y 的任何内容

            y :: p -> r
            x :: (p -> r) -> r -> _
    

    让我们调用最终结果q

            y :: p -> r
            x :: (p -> r) -> r -> q
    

    并按照给定的方式写出整个函数:

    (\x y -> x y . y) :: ((p -> r) -> r -> q) -> (p -> r) -> p -> q
    --                   └─────────x────────┘    └──y───┘
    

    这就是,重命名类型变量之后,和你开始的一样。

    【讨论】:

      猜你喜欢
      • 2015-06-12
      • 2021-10-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-04-19
      • 1970-01-01
      • 2020-01-27
      • 1970-01-01
      相关资源
      最近更新 更多