Haskell中的镜头与Clojure中的解构之间有什么相同点和不同点?

时间:2015-02-14 11:00:49

标签: haskell clojure lens lenses destructuring

假设:

  • 我想解析一个嵌套的JSON字符串。
  • 我知道Haskell鼓励用类型系统解决问题,而Clojure避开类型系统,更喜欢用数据结构解决问题。
  • 我知道在这两种语言中这个过程被称为 destructuring - 但它在Clojure中没有其他名称,而在Haskell中这也被称为使用镜头,所以我打电话给Clojure一个解构,继续前进

我们可以看到我们可以在Haskell中创建lens like this

{-# 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中进行解构like this

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中的解构有什么相似之处?

1 个答案:

答案 0 :(得分: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等等(就像成员名称一样)。他们分别获得GameUnitPoint并生成其各自成员的价值。如果必须手动定义这些函数(因为Haskell自动为所有记录类型定义了这些函数),它们看起来像这样:

_health (Unit {health = h}) = h

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

代码中的镜头为health。它包含函数_health(如上所述,它采用Unit并生成其健康状况)和函数(\unit v -> unit { _health = v }),它采用单位和值并生成一个新的单位,其健康状况已设置为该值。换句话说,镜头包含获取和设置单位健康的代码。镜头库现在包含各种功能,您可以使用它们来构图和使用这些镜头。

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