私は Haskell の世界の初心者であり、Lisp から移行しています。私は、Haskell の根本的に異なる世界観に適応しようとしています。私が新しくてエキサイティングだと思う多くのことの 1 つは、型システムです。私は Lisp として、Lisp の世界で非常に重要な関数を Haskell で実装しようと考えましたapply
。知らない人のために説明すると、 apply は関数と引数のリストを取り、それらの引数で関数を呼び出します。Scheme では、(apply + '(1 2 3))
を呼び出すのと同じで、(+ 1 2 3)
6 を返します。
私の Haskell コードは次のようになります。
apply x [] = x
apply f (x:xs) = apply (f x) xs
しかし、Haskell は次のように不満を述べています。
ERROR line 2 - Type error in function binding
*** Term : apply
*** Type : (b -> a) -> [b] -> a
*** Does not match : a -> [b] -> a
*** Because : unification would give infinite type
そして、私はその理由を理解していると思います。Apply の型は、与えられたリストの長さに応じて異なる必要があります。たとえば、3 つのアイテムのリストが与えられた場合、apply のタイプは:(a -> a -> a -> b) -> [a] -> b
である必要がありますが、6 つのアイテムのリストが与えられた場合、apply のタイプは: である必要があります(a -> a -> a -> a -> a -> a -> b) -> [a] -> b
。
私はこの恐ろしい回避策を試しました:
data FnOrDat a b = Dat b | Fn (a -> FnOrDat a b)
apply :: (FnOrDat a b) -> [a] -> (FnOrDat a b)
apply x [] = x
apply (Fn f) (x:xs) = apply (f x) xs
apply (Dat _) _ = error "Cannot apply something which is not a function!"
add a = Fn (\b -> Dat (a + b))
main = putStrLn $ show $ x where Dat x = apply (Fn add) [5,1]
これは機能しますが、関数としてはほとんどカウントされません。通常の関数apply
を渡すことができないためapply
、(厄介な) FnOrDat 抽象化を使用するために特別に作成された関数を使用する必要があります。4 つの数値を加算する関数を書きたい場合は、次のように書く必要があります。
add4 a = Fn (\b -> Fn (\c -> Fn (\d -> Dat (a + b + c + d))))
ええ。
apply
それで、私は何かが欠けていますか、それとも基本的に任意の長さのタプルを操作できる関数を求めるような汎用を求めていますか? apply
Haskell の静的に型付けされた世界観でも意味があるのでしょうか?