20

重複の可能性:
なぜそのような関数定義が haskell で許可されないのですか?

私は 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それで、私は何かが欠けていますか、それとも基本的に任意の長さのタプルを操作できる関数を求めるような汎用を求めていますか? applyHaskell の静的に型付けされた世界観でも意味があるのでしょうか?

4

3 に答える 3

11

apply関数に型を与えることができないので、Haskellではあまり役に立ちません。FnOrDatに見られるように、基本的にLisp言語をEDSLとしてHaskellに埋め込んで、何かを強制的に通過させています。

基本的に、任意の長さのタプルを操作できる関数を求めるような汎用的な適用を求めるのですか?

その通り。型の特定の便利な組み合わせの型クラスインスタンスを思い付くことができますが、一般的な可変個引数の必要性や使用法は実際にはありませんapply


ちなみに、過去10年間に開発されたライブラリ、ツール、言語機能のほとんどを見逃しているため、廃止されたHugsシステムではなく、GHCとHaskellプラットフォームへのアップグレードを検討する必要があります。

于 2012-05-26T15:21:01.980 に答える
4

ドンの説明にもかかわらず、foldl1 (+)実際にはリストのすべての要素を追加します。したがって、関数のファミリは、OP で説明されているようにfold非常に近いと言えます。apply

于 2012-05-26T15:36:48.567 に答える
1

... Lisp の世界で非常に重要な関数: apply。知らない人のために説明すると、apply は関数と引数のリストを受け取り、それらの引数で関数を呼び出します。Scheme では、(apply + '(1 2 3))は(+ 1 2 3) を呼び出すのと同じで、 6を返します。...

これは非常に簡単です:

foldr  (+) 0 [1,2,3]
foldr1 (+)   [1,2,3]

結果は 6 です。

リストの各要素に関数を適用するには:

map f list

例えば

map (2*) [1,2,3]

結果は [2,4,6]

これはあなたが探しているものですか?

于 2012-05-28T14:39:01.677 に答える