草庐IT

c# - 请确认或更正我的这个 Haskell 代码片段的 "English interpretation"

coder 2024-05-24 原文

我是一名 C# 开发人员,正在通过 "Real World Haskell" 工作为了真正理解函数式编程,所以当我学习 F# 时,我会真正理解它,而不仅仅是“在 F# 中编写 C# 代码”,可以这么说。

好吧,今天我遇到了一个我以为我理解了 3 次不同的例子,然后才看到我错过的东西,更新我的解释,然后递归(还有诅咒,相信我)。

现在我相信我确实理解了它,我在下面写了一个详细的“英文解释”。 Haskell 大师能否确认这种理解,或者指出我遗漏了什么?

注意:Haskell 代码片段(直接从书中引用)定义了一个自定义类型,该类型旨在与内置的 Haskell 列表类型同构。

Haskell 代码片段

data List a = Cons a (List a)
              | Nil
              defining Show

编辑:经过一些回复后,我看到了一个误解,但我不太清楚可以纠正该错误的 Haskell“解析”规则。所以我在下面包含了我原来的(不正确的)解释,然后是更正,然后是我仍然不清楚的问题。

编辑:这是我对片段 的原始(不正确)“英文解释”
  • 我正在定义一个名为“List”的类型。
  • List 类型是参数化的。它只有一个类型参数。
  • 有 2 个值构造函数可用于创建 List 的实例。一个值构造函数称为“Nil”,另一个值构造函数称为“Cons”。
  • 如果您使用“Nil”值构造函数,则没有字段。
  • “Cons”值构造函数只有一个类型参数。
  • 如果您使用“Cons”值构造函数,则必须提供 2 个字段。第一个必填字段是 List 的一个实例。第二个必填字段是 a 的一个实例。
  • (我故意省略了关于“定义表演”的任何内容,因为它不是我现在想要关注的部分)。

  • 更正后的解释如下(粗体更改)
  • 我正在定义一个名为“List”的类型。
  • List 类型是参数化的。它
    有一个类型参数。
  • 有2个值构造函数
    可用于制作实例
    名单。一个值构造函数是
    称为“Nil”和另一个值
    构造函数称为“缺点”。
  • 如果您使用“Nil”值构造函数,则没有字段。

    5.(此行已被删除……这是不准确的)“Cons”值构造函数只有一个类型参数。
  • 如果使用“Cons”值构造函数,则有 2 个字段
    必须提供。首先
    必填字段是 a 的一个实例。
    第二个必填字段是
    “List-of-a”的实例。
  • (我故意省略了关于“定义表演”的任何内容,因为它不是我现在想要关注的部分)。

  • 还不清楚的问题

    最初的困惑是关于“Cons a (List a)”的片段部分。事实上,这是我仍然不清楚的部分。

    人们已经指出,“Cons”标记之后的每一行都是一个类型,而不是一个值。所以这意味着这一行说“Cons 值构造函数有 2 个字段:一个是 'a' 类型,另一个是 'list-of-a' 类型。”

    了解这一点非常有帮助。然而,有些事情还不清楚。当我使用 Cons 值构造函数创建实例时,这些实例“解释”第一个 'a' 的意思是“将传入的值放在此处”。但是他们不会以相同的方式解释第二个“a”。

    例如,考虑这个 GHCI session :
    *Main> Cons 0 Nil
    Cons 0 Nil
    *Main> Cons 1 it
    Cons 1 (Cons 0 Nil)
    *Main> 
    

    当我键入“Cons 0 Nil”时,它使用“Cons”值构造函数来创建 List 的实例。从 0 开始,它得知类型参数是“Integer”。到目前为止,没有混淆。

    但是,它也确定了 Cons 的第一个字段的值是 0。但它没有确定第二个字段的值……它只确定第二个字段的类型为“List Integer”。

    所以我的问题是,为什么第一个字段中的“a”表示“该字段的类型是 'a',该字段的值是 'a'”,而第二个字段中的“a”仅表示“类型”这个字段是'List of a'”?

    编辑:我相信我现在已经看到了曙光,多亏了一些回应。让我在这里说明一下。 (如果不知何故它在某些方面仍然不正确,请务必让我知道!)

    在代码片段“Cons a (List a)”中,我们说“Cons”值构造函数有两个字段,第一个字段的类型为“a”,第二个字段的类型为“List of a” '。

    这就是我们要说的! 特别是,我们对值(value)观一无所知!这是我遗漏的一个关键点。

    稍后,我们要创建一个实例,使用“Cons”值构造函数。我们在解释器中输入:“Cons 0 Nil”。此 明确告诉 Cons 值构造函数使用 0 作为第一个字段的值,并使用 Nil 作为第二个字段的值。

    这就是全部。一旦您知道值构造函数定义只指定类型,一切就变得清晰了。

    感谢大家的有用回复。正如我所说,如果仍有任何问题,请务必告诉我。谢谢。

    最佳答案

    • The "Cons" value constructor has a single type parameter.


    不:您在声明 data List a 时已经对其进行了参数化。 .一个有效的属性是,如果我有一个 Nil::List Int,我不能将它与 Nil::List Char 互换。

    • If you use the "Cons" value constructor, there are 2 fields which must be provided. The first required field is an instance of List. The second required field is an instance of a.


    你已经把它交换了:第一个必填字段是 a 的实例,第二个字段是 List 的实例。

    This chapter of Real World Haskell可能会感兴趣。

    Thanks. That is the chapter I'm on right now. So ... when the code says "Cons a (List a)", I thought the "Cons a" part of that was stating that the Cons value constructor was parameterised. They haven't yet covered the syntax for parameterised types, so I guessed that the syntax must require re-stating "a" if you intend to use a. But you're saying that's not necessary? And therefore that's not what that "a" means?



    不。一旦我们在我们的类型中声明了一个参数,我们就可以重用它,否则说“应该在那里使用那个类型”。有点像 a -> b -> a类型签名: a 正在参数化类型,但是我必须使用相同的 a 作为返回值。

    OK, but this is confusing. It seems that the first "a" means "the first field is an instance of a",



    不,那不是真的。它只是意味着数据类型参数化了某种类型 a。

    and it ALSO means "the first field has the same value as the value they passed in for a". In other words, it specifies type AND value.



    不,这也不是真的。

    这是一个很有启发性的例子,你可能见过也可能没见过它的语法:

    foo::Num a => a -> a

    对于一个函数来说,这是一个相当标准的签名,它接受一个数字并对它做一些事情并给你另一个数字。不过,在 Haskell 中,我所说的“数字”实际上是一些实现“Num”类的任意类型“a”。

    因此,这解析为英语:

    Let a indicate a type implementing the Num typeclass, then the signature of this method is one parameter with the type a, and the return value of the type a



    类似的事情发生在数据上。

    我还发现 Cons 规范中的 List 实例也让您感到困惑:解析时要非常小心:而 Cons 指定了一个构造函数,它基本上是 Haskell 要将数据包装到的一种模式,(列表 a) 看起来像一个构造函数,但实际上只是一个类型,如 Int 或 Double。 a 是一种类型,不是该术语任何意义上的值。

    编辑:回应最近的编辑。

    我认为首先需要进行解剖。然后我会逐条处理你的问题。

    Haskell 数据构造函数有点奇怪,因为你定义了构造函数签名,而不必做任何其他脚手架。 Haskell 中的数据类型没有任何成员变量的概念。 (注意:有一种替代语法更适合这种思维方式,但我们现在先忽略它)。

    另一件事是 Haskell 代码很密集;它的类型签名就像那样。所以希望看到在不同的上下文中重复使用相同的符号。类型推断在这里也发挥着重要作用。

    所以,回到你的类型:

    数据列表 a = 缺点 a(列表 a)
    |零

    我把它分成几部分:

    数据列表a

    这定义了类型的名称,以及它稍后将拥有的任何参数化类型。请注意,您只会看到它出现在其他类型签名中。

    缺点a(列表a)|


    这是数据构造函数的名称。这不是一种类型。但是,我们可以对其进行模式匹配,ala:

    foo::列出一个 -> Bool
    foo 无 = 真

    注意 List a 是签名中的类型,而 Nil 既是数据构造函数,也是我们模式匹配的“事物”。

    缺点a(列表a)

    这些是我们插入构造函数的值的类型。 Cons 有两个条目,一个是 a 类型,一个是 List a 类型。

    So my question is, why does "a" in the first field mean "the type of this field is 'a' and the value of this field is 'a'", while "a" in the second field means only "the type of this field is 'List of a'"?



    简单:不要把它当作我们指定类型;想想它有 Haskell 正在推断它的类型。因此,出于我们的意图和目的,我们只是在其中粘贴 0,在第二部分粘贴 Nil。然后,Haskell 查看我们的代码并思考:
  • 嗯,我想知道 Cons 0 Nil 的类型是什么
  • 好吧, Cons 是 List a 的数据构造函数。我想知道 List a 的类型是什么
  • 嗯,a 用在第一个参数中,所以因为第一个参数是一个 Int(另一种简化;0 实际上是一个奇怪的东西,被归类为 Num),所以这意味着 a 是一个 Num
  • 嘿,好吧,这也意味着 Nil 的类型是 List Int,尽管实际上没有任何内容可以说

  • (注意,这实际上并不是它的实现方式。Haskell 在推断类型时可以做很多奇怪的事情,这就是错误消息很糟糕的部分原因。)

    关于c# - 请确认或更正我的这个 Haskell 代码片段的 "English interpretation",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/775730/

    有关c# - 请确认或更正我的这个 Haskell 代码片段的 "English interpretation"的更多相关文章

    1. ruby-on-rails - rails : "missing partial" when calling 'render' in RSpec test - 2

      我正在尝试测试是否存在表单。我是Rails新手。我的new.html.erb_spec.rb文件的内容是:require'spec_helper'describe"messages/new.html.erb"doit"shouldrendertheform"dorender'/messages/new.html.erb'reponse.shouldhave_form_putting_to(@message)with_submit_buttonendendView本身,new.html.erb,有代码:当我运行rspec时,它失败了:1)messages/new.html.erbshou

    2. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

      我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

    3. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

      如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

    4. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

      在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

    5. ruby - 检查 "command"的输出应该包含 NilClass 的意外崩溃 - 2

      为了将Cucumber用于命令行脚本,我按照提供的说明安装了arubagem。它在我的Gemfile中,我可以验证是否安装了正确的版本并且我已经包含了require'aruba/cucumber'在'features/env.rb'中为了确保它能正常工作,我写了以下场景:@announceScenario:Testingcucumber/arubaGivenablankslateThentheoutputfrom"ls-la"shouldcontain"drw"假设事情应该失败。它确实失败了,但失败的原因是错误的:@announceScenario:Testingcucumber/ar

    6. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

      我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

    7. ruby-on-rails - 迷你测试错误 : "NameError: uninitialized constant" - 2

      我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test

    8. ruby-on-rails - 相关表上的范围为 "WHERE ... LIKE" - 2

      我正在尝试从Postgresql表(table1)中获取数据,该表由另一个相关表(property)的字段(table2)过滤。在纯SQL中,我会这样编写查询:SELECT*FROMtable1JOINtable2USING(table2_id)WHEREtable2.propertyLIKE'query%'这工作正常:scope:my_scope,->(query){includes(:table2).where("table2.property":query)}但我真正需要的是使用LIKE运算符进行过滤,而不是严格相等。然而,这是行不通的:scope:my_scope,->(que

    9. 使用 ACL 调用 upload_file 时出现 Ruby S3 "Access Denied"错误 - 2

      我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file

    10. ruby-on-rails - 浏览 Ruby 源代码 - 2

      我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

    随机推荐