簡體   English   中英

函數式編程中的條件“分配”

[英]Conditional “assignment” in functional programming

我正在編寫沒有副作用的程序,但是我的代碼不太可讀。 考慮以下代碼:

(let [csv_data (if header_row (cons header_row data_rows) data_rows)]
)

我正在嘗試在代碼塊中使用csv_data 有沒有一種以header_row為條件的干凈方法? 我看過if-let ,但看不到這有什么幫助。

我也遇到了類似的情況,即使用功能性for循環將結果綁定到局部變量,並且代碼看起來像一堆表達式。

在很多情況下,我真的必須創建一個單獨的輔助函數嗎? 我在這里想念什么?

使用cond->>

(let [csv_data (cond->> data_rows
                 header_row (cons header-row)]
   )

它的工作方式類似於常規的->>宏,但是在每個線程形式之前必須放置一個測試表達式,以確定是否將使用線程形式。

還有cond-> 在此處閱讀有關線程宏的更多信息: 官方線程宏指南

首先,請勿使用下划線,而應使用破折號。

第二,輔助功能很少沒有錯。 畢竟,這似乎是處理您的特定數據格式的要求。

第三,如果您可以更改數據,以便跳過那些決定,並對所有極端情況進行統一表示,那就更好了。 標題行包含另一種數據(列名?),因此您可能希望將它們分開:

(let [csv {:header header :rows rows}]
  ...)

或者,也許在某些時候,“頁眉”和“行”可以是同一類型:行序列。 然后,您可以直接連接它們。 ensure-x習慣用法是標准化數據的一種非常常用的方法:

(defn ensure-list [data]
  (and data (list data)))

例如:

user=> (ensure-list "something")
("something")
user=> (ensure-list ())
(())
user=> (ensure-list nil)
nil

因此:

(let [csv (concat (ensure-list header) rows)]
  ...)

我會提出一個實用程序宏。 像這樣:

(defmacro update-when [check val-to-update f & params]
  `(if-let [x# ~check]
     (~f x# ~val-to-update ~@params)
     ~val-to-update))

user> (let [header-row :header
            data-rows [:data1 :data2]]
        (let [csv-data (update-when header-row data-rows cons)]
          csv-data))
;;=> (:header :data1 :data2)

user> (let [header-row nil
            data-rows [:data1 :data2]]
        (let [csv-data (update-when header-row data-rows cons)]
          csv-data))
;;=> [:data1 :data2]

它非常通用,可以讓您完成更復雜的任務,而不僅僅是簡單的調整。 例如,如果要檢查是否為真,您想反轉一些列,並連接另一個列表...

user> (let [header-row :header
            data-rows [:data1 :data2]]
        (let [csv-data (update-when header-row data-rows
                                    (fn [h d & params] (apply concat (reverse d) params))
                                    [1 2 3] ['a 'b 'c])]
          csv-data))

;;=> (:data2 :data1 1 2 3 a b c)

@amalloy注意到更新 ,此宏應該是一個函數:

(defn update-when [check val-to-update f & params]
  (if check
     (apply f check val-to-update params)
     val-to-update))

在考慮了命名空間中單行幫助函數的“成本”之后,我想出了一個局部函數:

(let [merge_header_fn   (fn [header_row data_rows] 
                          (if header_row 
                            (cons header_row data_rows) 
                            data_rows))
      csv_data (merge_header_fn header_row data_rows) ]
  ...
  <use csv_data>
  ...
) 

除非有人能提出一種更優雅的處理方式,否則我將以此為答案。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM