3 回答

TA貢獻1817條經驗 獲得超14個贊
很難給apply
函數賦一個靜態類型,因為它的類型取決于(可能是異構的)list參數的類型。在Haskell中編寫此函數的方法至少有兩種我能想到的方法:
用反射
我們可以推遲應用程序的類型檢查直到運行時:
import Data.Dynamicimport Data.Typeable apply :: Dynamic -> [Dynamic] -> Dynamic apply f [] = f apply f (x:xs) = apply (f `dynApp` x) xs
請注意,現在Haskell程序可能會在運行時因類型錯誤而失敗。
編輯:我無法想出一種方法來編寫它,而不使用動態類型或hlists /存在。很想看到一個例子

TA貢獻1789條經驗 獲得超10個贊
我喜歡Sjoerd Visscher的回復,但擴展 - 特別是IncoherentInstances
在這種情況下用于部分應用的擴展- 可能有點令人生畏。這是一個不需要任何擴展的解決方案。
首先,我們定義一個函數的數據類型,知道如何處理任意數量的參數。你應該a
在這里讀作“參數類型”,并b
作為“返回類型”。
data ListF a b = Cons b (ListF a (a -> b))
然后我們可以編寫一些(Haskell)函數來實現這些(可變參數)函數。我將F
后綴用于恰好在Prelude中的任何函數。
headF :: ListF a b -> b headF (Cons b _) = b mapF :: (b -> c) -> ListF a b -> ListF a c mapF f (Cons v fs) = Cons (f v) (mapF (f.) fs)partialApply :: ListF a b -> [a] -> ListF a b partialApply fs [] = fs partialApply (Cons f fs) (x:xs) = partialApply (mapF ($x) fs) xs apply :: ListF a b -> [a] -> b apply f xs = headF (partialApply f xs)
例如,該sum
函數可以被認為是一個可變函數:
sumF :: Num a => ListF a a sumF = Cons 0 (mapF (+) sumF)sumExample = apply sumF [3, 4, 5]
但是,我們還希望能夠處理正常的函數,這些函數不一定知道如何處理任何數量的參數。那么該怎么辦?好吧,就像Lisp一樣,我們可以在運行時拋出異常。下面,我們將使用f
非可變函數的簡單示例。
f True True True = 32f True True False = 67f _ _ _ = 9tooMany = error "too many arguments"tooFew = error "too few arguments"lift0 v = Cons v tooMany lift1 f = Cons tooFew (lift0 f)lift2 f = Cons tooFew (lift1 f)lift3 f = Cons tooFew (lift2 f)fF1 = lift3 f fExample1 = apply fF1 [True, True, True]fExample2 = apply fF1 [True, False]fExample3 = apply (partialApply fF1 [True, False]) [False]
當然,如果你不喜歡定義的樣板lift0
,lift1
,lift2
,lift3
,等分開,那么你就需要啟用一些擴展。但是如果沒有他們,你可以走得很遠!
以下是如何推廣到單個lift
函數的方法。首先,我們定義一些標準的類型級數:
{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, TypeFamilies, UndecidableInstances #-}data Z = Znewtype S n = S n
然后介紹用于提升的類型類。您應該將類型讀I n a b
作“ 作為參數的n
副本a
,然后返回類型b
”。
class Lift n a b where type I n a b :: * lift :: n -> I n a b -> ListF a binstance Lift Z a b where type I Z a b = b lift _ b = Cons b tooManyinstance (Lift n a (a -> b), I n a (a -> b) ~ (a -> I n a b)) => Lift (S n) a b where type I (S n) a b = a -> I n a b lift (S n) f = Cons tooFew (lift n f)
以下是使用f
之前使用廣義電梯重寫的示例:
fF2 = lift (S (S (S Z))) f fExample4 = apply fF2 [True, True, True]fExample5 = apply fF2 [True, False]fExample6 = apply (partialApply fF2 [True, False]) [False]

TA貢獻1796條經驗 獲得超10個贊
不,它不能。f
并且f x
是不同的類型。由于haskell的靜態類型性質,它不能承擔任何功能。它必須采用特定類型的功能。
假設f
傳入類型a -> b -> c
。然后f x
有類型b -> c
。但a -> b -> c
必須具有相同的類型a -> b
。因此,類型的函數a -> (b -> c)
必須是類型的函數a -> b
。所以b
必須是相同的b -> c
,這是一種無限類型b -> b -> b -> ... -> c
。它不可能存在。(繼續替代b -> c
的b
)
添加回答
舉報