【问题标题】:Haskell: beginner function syntax confusionHaskell:初学者函数语法混乱
【发布时间】:2011-10-26 20:16:29
【问题描述】:

我目前正在尝试学习 Haskell,但在理解语法方面遇到了困难。以map函数为例:

map :: (s -> t) -> [s] -> [t]
map f [] = []
map f (x:xs) = f x : map f xs

我了解该函数的作用,并且 map 有一个函数 f :: s -> t 作为参数。但我将map :: (s -> t) -> [s] -> [t] 读为“map 是一个函数,它将函数映射从 s 映射到 t 到 s 再到 t”,这显然是错误的。有人可以帮我解决这个问题吗?

【问题讨论】:

    标签: haskell


    【解决方案1】:

    (s -> t) -> [s] -> [t] 类型可以通过两种方式读取。一种方法是将其视为两个参数的函数,第一个是s -> t 类型的函数,第二个是[s] 类型的列表。返回值的类型为[t]

    另一种方式是理解函数箭头是右关联的,所以类型等价于(s -> t) -> ([s] -> [t])。在这种解释下,map 是一个从元素到元素 s -> t 的函数,并将其转换为从列表到列表 [s] -> [t] 的函数。

    同样,在使用函数时,您可以将map foo xs 视为将函数map 应用于fooxs 两个参数。或者,由于函数应用程序是-关联的,您可以将其视为(map foo) xs,将map 应用于单个参数foo 以返回一个新函数,然后将其应用于@ 987654337@.

    由于 Haskell 函数是 curried,因此这只是查看完全相同事物的两种方式。

    【讨论】:

      【解决方案2】:

      定义几个类型别名可能会有所帮助,以使所有这些箭头和括号的作用更加明确:

      type F1 a b = a -> b  -- type synonym for single-argument functions
      type List a = [a]  -- type synonym for lists
      

      所以现在你可以将map的类型签名写成:

      map :: F1 s t -> List s -> List t
      

      如果您更熟悉 Java 或 C++ 或其他什么,它在语法上看起来更像:

      List<T> map(F1<S, T> fun, List<S> list); // applies fun to each element in list
      

      所以你可以这样想:map 接受一个函数和一个列表,然后返回另一个列表。但是,由于函数在 Haskell 中是 curried,因此您不必一次传递所有参数。您可以部分应用 map 来解决它的第一个参数。所以实际上它的类型签名更像是:

      F1<List<S>, List<T>> map(F1<S, T> fun); // returns a function that applies fun to each element in a list
      

      ...当您使用 fun 参数调用 map 时,它会为您提供类似于以下内容的内容:

      List<T> mapFun(List<S> list); // applies fun to each element in list
      

      现在回到 Haskell:您可以将 map :: (s -&gt; t) -&gt; [s] -&gt; [t] 读为:

      • "map 接受一个从 st 的函数,以及一个 s 的列表,并返回一个 的列表t"
      • "map 将一个函数从 s 转换为 t,并将其转换为一个从 s 列表到 的函数em>t 列表"

      前者很好;后者更有帮助。

      【讨论】:

      • 警告:如果您熟悉 Java 或其他什么,最好完全忽略我的回答,除了最后一点;)
      • 同意。所有的“”和“”都让我觉得“不,现在我理解了haskell..他们再次改变它和/或想出另一个扩展”:-)
      【解决方案3】:

      “map 是一个函数,它将一个(从 s 到 t 的函数)映射到一个(s 的列表)上,给出一个(t 的列表)”呢? 这是将类型签名直接翻译成英文(虽然不是很优雅的英文)。

      【讨论】:

      • 不够通用;例如,您将如何翻译类型签名zipWith :: (a -&gt; b -&gt; c) -&gt; [a] -&gt; [b] -&gt; [c]?术语“将 blah 映射到 blah 的函数”源自您所知道的 map 所做的,而不是源自其类型签名。对于zipWith 示例,我会说它“将一个函数从 ab 转换为 c,并将其变成一个新的从a列表b列表c列表的函数。"
      【解决方案4】:

      从末尾读取签名:-&gt; [t] 表示返回t 的列表。其余的是“常规”参数。

      因此,map 采用从 s 生成 t 的函数和 s 的列表。

      现在很简单:获取一个函数s-&gt;t,将其应用于[s] 的每个元素,其结果为[t]

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-05-30
        • 2014-05-04
        • 2015-05-23
        • 2018-12-22
        • 1970-01-01
        • 2012-12-31
        • 1970-01-01
        • 2011-02-13
        相关资源
        最近更新 更多