簡體   English   中英

將函數應用於 Haskell 中遞歸數據類型的每個元素的最優雅/最簡單的方法?

[英]Most elegant/ simple way to apply a function to every element of a recursive data type in Haskell?

上下文(可能不是真的需要,你可以跳過這個,問題在底部):我正在准備 Haskell 的考試,很可能會有一個問題,我們得到了一個數據類型並且必須將函數應用於該數據類型的每個元素。 例如,它可能是這樣的

data ToDoList = Task String | HighPriority [ToDoList] | LowPriority [ToDoList] | FreeTime [ToDoList]
    deriving (Eq, Show)

練習可以是“編寫一個函數,該函數接受重命名函數 f :: String -> String 和 ToDoList,並返回更新的 ToDoList,其中每個任務都根據 f 重命名。”

可能的解決方案:

在前幾年的解決方案中,他們通過混合使用模式匹配、遞歸和映射來非常巧妙地解決這個問題。 他們定義了原子值和復合/遞歸數據類型的情況,他們將函數映射到數據類型的數組上(如果需要,我可以提供示例)。

對於我相當復雜的方法(這也行不通),我還為原子值定義了基本情況,然后嘗試對數組進行模式匹配,在元素上調用函數並在之后附加它們; 函數定義的一種情況是(不起作用):

rename (HighPriority []) = HighPriority []
rename (HighPriority (t:ts)) = HighPriority ((rename f t):[rename f (HighPriority ts)])

我的問題:在遞歸數據類型上迭代函數有哪些簡單快捷的方法?

編輯:抱歉造成混淆,是的,我打算用“ToDoList”列表定義數據類型。

對於該數據類型,您可以將String值應用於Task案例中的函數f ,並在所有其他案例中使用map

rename :: (String -> String) -> ToDoList -> ToDoList
rename f (Task x)          = Task (f x)
rename f (HighPriority xs) = HighPriority (map (rename f) xs)
rename f (LowPriority xs)  = LowPriority (map (rename f) xs)
rename f (FreeTime xs)     = FreeTime (map (rename f) xs)

雖然這不是考試的合適答案,但對於未來在實際代碼中遇到類似問題的 Stack Overflow 用戶來說,值得指出的是uniplate包很好地處理了這種問題。 您必須為您的數據類型提供適當的Uniplate實例; 最簡單的方法是派生Data實例並導入Data.Generics.Uniplate.Data包:

{-# LANGUAGE DeriveDataTypeable #-}

import Data.Data
import Data.Generics.Uniplate.Data

data ToDoList
  = Task String
  | HighPriority [ToDoList]
  | LowPriority [ToDoList]
  | FreeTime [ToDoList]
  deriving (Eq, Show, Data)

在此之后,您可以通過定義一個僅進行所需本地更改的輔助函數來使用uniplatetransform函數編寫rename

rename :: (String -> String) -> ToDoList -> ToDoList
rename f = transform f'
  where f' (Task s) = (Task (f s))
        f' x = x

請注意,輔助函數f' :: ToDoList -> ToDoList僅修改任務字符串,同時傳遞其他所有內容不變,但transform函數確保它會在出現ToDoList任何地方遞歸應用到整個數據結構中:

> import Data.Char
> rename (map toUpper) $ HighPriority [LowPriority [Task "one", Task "two"], Task "three"]
HighPriority [LowPriority [Task "ONE",Task "TWO"],Task "THREE"]

暫無
暫無

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

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