【问题标题】:Haskell function signature confusionHaskell 函数签名混淆
【发布时间】:2019-07-02 20:02:13
【问题描述】:

我正在尝试学习 Haskell,但我遇到了一些问题。到目前为止,我已经明白函数签名符合这个约定:

<name> :: <type constraint A> => <input type A> -> <input type B> -> .. <input type X> -> <return type>

所以,我目前理解的一些例子是:

-- Returns input + 2
add2 :: Int -> Int
add2 x = x + 2

-- Returns the result of applying a function that takes an int and returns an int on an input int
adds2 :: (Int -> Int) -> Int -> Int
adds2 func x = func x

-- Returns a String with "Hello" prepended to the front
sayHello :: String -> String
sayHello name = "Hello " ++ name

然后我遇到了这件事,这让我很困惑:

mate :: RandomGen g => Gene -> Gene -> Rand g Gene

我知道函数名称是mate,它有一个类型约束,其中g 必须是RandomGen 类型,然后它将两个Gene 类型的值作为输入。

然而,真正让我困惑的是返回类型。您如何解释这一点,任何人都可以向新手 Haskeller 解释一下吗?

【问题讨论】:

  • 您的描述看起来正确。对于最后一种类型,请注意Rand g Gene 是一个单子类型,通过将单子Rand g 应用于Gene 类型获得。如果您还不熟悉 monad,那么要完全理解其后果并不容易。尽管如此,在英语中,Rand g Gene 的值是对能够读取和写入类型为g 的 RNG 状态变量并生成Gene 值作为结果的计算的描述。更简洁地说,mate 返回一个Gene,但结果是随机的,所以它不是一个常规的确定性函数..
  • 啊,可怕的 monad.... 每次我试图陷入 Haskell 时,我都会碰到这个“Monad”墙,我读过的所有资源都接近掌握这个概念但它似乎从来没有点击过:-(
  • 您实际上并不需要了解有关 Monads 的任何事情来理解类型签名。您只需要知道Rand 是一个“类型构造函数”,它接受2 个参数来创建一个“具体”类型。从技术上讲,我们说Rand 是一个“种类”为* -&gt; * -&gt; * 的类型(您也可以看到写为Type -&gt; Type -&gt; Type),这完全类似于具有a -&gt; b -&gt; c 类型的函数——它是一个“ types”,它需要 2 种类型并产生另一种。 Maybe 是一个简单的例子,你可能已经知道了 - 它有一种 * -&gt; *(它需要 1 个类型参数)。
  • 将约束读取为“g 必须具有类型类 RandomGeninstance”。

标签: haskell


【解决方案1】:

如果您为自己定义了一种数据类型,例如

data MyType = A Int String

那么A,您的数据构造函数,实际上将是一个具有类型的函数

A :: Int -> String -> MyType

你会这样调用它来产生MyType的值。

A 42 "hello"

这就是数据构造函数。

Haskell 也有类型构造函数。 Rand 是其中之一。就像函数值具有定义如何应用它们的函数类型一样,类型构造函数具有确定如何应用它们的“函数”种类。像IntString 这样的常规旧类型拼写为*Rand 的类型是一个类型构造函数,是* -&gt; * -&gt; *:它接受两种类型并从中生成一个类型。

因此,当您将Rand 应用于gGene 类型时,您将获得函数的返回类型,即Rand g Gene

欲了解更多信息,请参阅this chapter of Learn You A Haskell

(“好的,但是...什么是Rand g Gene?”,我听到你问了。好吧,假设你的意思是this RandRand g Gene 是一个代表计算的值,它会产生@987654343 @如果你在能够运行Rand g的东西上运行它,比如runRand。现在,这不是你可以用Rand g Gene做的唯一事情,因为它恰好Rand g是一个.. . dun dun dun... monad!有关该概念的更多信息,您真的应该阅读LYAH 之类的内容...有很多预备知识要通过才能完整解释给新手。)

【讨论】:

  • 你和Maybe合作了吗? Maybe 是一个类型构造函数,所以Maybe Int 是一个有效类型,而Maybe String 也是如此。 Rand 是一回事;它只是采用两个参数,而不是 Maybe 采用的一个。
  • @ThomasCook 它更像mate :: RandomGen g =&gt; Gene -&gt; Gene -&gt; (g -&gt; (g, Gene)),最多一些newtype 包装器。 IE。获取旧的 RNG 种子 g,并输出下一个种子以及 Gene 结果。也许这不是第一个最容易理解的单子。
  • 你理解一次单子就像你理解一次对象一样。一旦你知道了一个对象是什么(比如在 Java 中),用它们编程就容易多了,但是每个单独的对象仍然有它自己需要学习的怪癖。同样,一旦你了解了 monad,它们就会自然而然地出现,但每种类型的 monad 仍然有自己的特点。
  • 绝对值得。五年前我开始学习 Haskell,但我仍然不一定称自己为专家。直到至少学习一年后,我才对 monads 有深刻的理解。你并不落后;这是正常的,一旦你得到它,它会极大地改进你的编程,不仅仅是在 Haskell 中,而是在所有语言中。
  • 您将能够使用 RX observables 作为 monad 的 示例。并且特别熟悉mapflatMap 将有助于理解这些函数的泛化如何在其他单子中工作。但我认为 Silvio 的类比是正确的:monad 的概念就像 class 的概念——例子无处不在,理解这个概念是什么可能需要从很多方面建立直觉。具体例子。
猜你喜欢
  • 2013-12-26
  • 1970-01-01
  • 2018-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-26
  • 2011-09-10
  • 2015-06-11
相关资源
最近更新 更多