簡體   English   中英

Haskell,是否可以創建一個咖喱函數,可以存儲任意數量的元組元素

[英]Haskell, is it possible to create a curry function that can curry any number of tuple elements

當前的curry函數接受一個接受2個元素元組的函數,並允許將結果函數curry或部分應用。

let x = curry (\(x, y) -> x + y)
x 1 2 -- 3

是否可以創建一個咖喱函數來處理元組中包含N個元素的函數?

我嘗試創建它,但我不確定1:類型簽名,2:如何反轉參數。

curryN f 0 = f
curryN f n = \a -> (curryN (f) (n-1)) a

curryN (\(x, y, z) -> x + y + z) 3
-- I assume it looks something like: \a -> (\a -> (\a -> (f) a) a) a but I'm not sure

要么

curryN f 0 =  f
curryN f n = curryN (\a - > f a) (n -1)

另外,這樣的功能可以發現元素的數量,而不是需要告訴數字是多少?

實現此類功能的方法之一是使用GHC.Generics 使用這種方法,我們甚至不需要傳遞許多參數(或元組大小)。 這是因為有一個為元組定義的Generic實例,它有效地將元組轉換為樹結構(類型為Rep a ),然后我們可以從右向左遍歷(使用延續傳遞樣式),沿途生成curried函數並打包將這些參數的值轉換為相同的Rep a結構,然后將其轉換為具有to function的元組並傳遞給原始的非curried函數參數。 該代碼僅使用的參數的類型級樹( from沒有使用功能),因為我們產生元組而不是接收它。 這種方法的唯一限制是Generic僅定義為最多八個元素的元組。

{-# LANGUAGE TypeOperators, MultiParamTypeClasses,
  FlexibleInstances, UndecidableInstances,
  TypeFamilies, ScopedTypeVariables #-}

import GHC.Generics


-- | class for `curryN` function
class CurryN t r where
    type CurriedN t r :: *
    curryN :: (t -> r) -> CurriedN t r

-- | Implementation of curryN which uses GHC.Generics
instance (Generic t, GCurryN (Rep t) r) => CurryN t r where
    type CurriedN t r = GCurriedN (Rep t) r
    curryN f = gcurryN (f . to)

-- | Auxiliary class for generic implementation of `curryN`
--   Generic representation of a tuple is a tree of its elements
--   wrapped into tuple constructor representation
--   We need to fold this tree constructing a curried function
--   with parameters corresponding to every elements of the tuple
class GCurryN f r where
    type GCurriedN f r :: *
    gcurryN :: (f p -> r) -> GCurriedN f r

-- | This matches tuple definition
--   Here we extract tree of tuple parameters and use other instances to "fold" it into function
instance (GCurryN f r) => GCurryN (D1 e1 (C1 e2 f)) r where
    type GCurriedN (D1 e1 (C1 e2 f)) r = GCurriedN f r
    gcurryN c = gcurryN (\t -> c (M1 (M1 t)))

-- | A node of the tree (combines at least two parameters of the tuple)
instance (GCurryN b r, GCurryN a (GCurriedN b r)) => GCurryN (a :*: b) r where
    type GCurriedN (a :*: b) r = GCurriedN a (GCurriedN b r)
    gcurryN c = gcurryN (\a -> gcurryN (\b -> c (a :*: b)))

-- | A leaf of the tree (a single tuple parameter)
instance GCurryN (S1 NoSelector (Rec0 a)) r where
    type GCurriedN (S1 NoSelector (Rec0 a)) r = a -> r
    gcurryN c = \a -> c $ M1 (K1 a)


-- Examples of usage
t2 = curryN (uncurry (&&))

t3 = curryN (\(a,b,c) -> a + b + c)

t4 = curryN (\(a,b,c,d) -> ((a , b) , (c , d)))

tf = curryN (\(f,a,xs) -> foldr f a xs)

t5 = curryN (\(a,b,c,d,e) -> (a ++ b , c - d, not e))

t7 = curryN (\(a1,a2,a3,a4,a5,a6,a7) -> a7)

暫無
暫無

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

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