1

假设:

  • 我想解析一个嵌套的 JSON 字符串。
  • 我知道 Haskell 鼓励用类型系统解决问题,而 Clojure 避开类型系统,更喜欢用数据结构解决问题。
  • 我知道在这两种语言中,这个过程都被称为解构——但它在 Clojure 中没有另一个名字,而在 Haskell 中,这也被称为使用 lens,所以我将 Clojure 称为解构和移动上

我们可以看到我们可以在 Haskell中创建这样的镜头:

{-# LANGUAGE TemplateHaskell #-}

import Control.Lens

initialState :: Game
initialState = Game
    { _score = 0
    , _units =
        [ Unit
            { _health = 10
            , _position = Point { _x = 3.5, _y = 7.0 }
            }
        ]
    }

health :: Lens' Unit Int
health = lens _health (\unit v -> unit { _health = v })

它的目的是从数据结构中获取health值。game

我们可以在 Clojure中进行这样的解构:

user=> (def book {:name "SICP" :details {:pages 657 :isbn-10 "0262011530"}})
#'user/book

user=> (let [{name :name {pages :pages isbn-10 :isbn-10} :details} book]
     (println "name:" name "pages:" pages "isbn-10:" isbn-10))
name: SICP pages: 657 isbn-10: 0262011530

目的是从嵌套结构中获取名称、页面等的嵌套值。

在这两种情况下,您都提出了一种从嵌套结构中可重用检索值的机制。

我的问题是:Haskell 中的镜头和 Clojure 中的解构有何异同?

4

1 回答 1

3

您的 Clojure 代码将在 Haskell 中最接近地表达为:

book :: Book
book = Book {name = "SICP", details = Details {pages = 657, isbn_10: "0262011530"}}

main = do
  let Book {name = name, details = Details {pages = pages, isbn_10 = isbn_10}} = book
  putStrLn $ "name:" ++ name ++ "pages:" ++ (show pages) ++ "isbn-10:" ++ isbn-10

这里我们使用 Haskell 的模式匹配,它基本上是 Clojure 解构绑定的更一般形式,来获取记录的内容。这与镜头无关。

现在让我们用镜头来看看你的 Haskell 代码。此代码具有三种记录类型,Game、Unit 和 Point,并且这些类型都有一组自动定义的函数来访问其成员而无需模式匹配。这些函数称为_score_health_x(就像成员名称一样)。它们分别取 aGameUnitPoint产生各自成员的值。如果这些函数必须手动定义(因为 Haskell 自动为所有记录类型定义了这些函数),它看起来像这样:

_health (Unit {health = h}) = h

到目前为止,这仍然与镜头无关。

代码中的镜头是health。它包含函数_health(如前所述,它接受 aUnit并产生其生命值)和函数(\unit v -> unit { _health = v }),它接受一个单位和一个值并产生一个其生命值已设置为该值的新单位。换句话说,镜头包含获取和设置单位健康状况的代码。镜头库现在包含可用于构图和使用此类镜头的各种功能。

所以回答你的问题:镜头和解构之间没有相似之处。

于 2015-02-14T13:24:34.777 回答