5

Haskellのflip関数は、関数の最初の 2 つの引数の位置を切り替えるために使用されます。

flip :: (a -> b -> c) -> b -> a -> c
flip f y x = f x y

同様に、3 つの引数をローテーションする関数を作成できます。

rot :: (a -> b -> c -> d) -> b -> c -> a -> d
rot f y z x = f x y z

この概念は、任意の数の引数をカレー化する関数に拡張できますか?

型の関数が与えられた場合a -> ... -> z、次の型の関数を書くことは可能ですか?

(a -> ... -> z) -> ... -> a -> z

->演算子が右結合であることは知っています。したがって... -> z、分割することはできません。それにもかかわらず、私は確かに知りたいです。

4

2 に答える 2

7

そうです、これはできません。任意の数の引数に対してパターン マッチを行う必要がありますが、それを行う方法はありません。

Template Haskell を使用して、さまざまなアリティの一連の回転関数を生成できますが、生成する数を常に事前に決定する必要があり、真に汎用的な関数ではなく、それらを記述するためのショートカットにすぎません。

関数がたまたま引数をリスト (eew) として受け取った場合、同様のことを行うことができますが、これには、引数の型が同種でなければならないという顕著な欠点もあります。

于 2013-03-14T10:57:03.457 に答える
2

技術的には、拡張機能rotを使用して実装できます (ただし、おそらくそうすべきではありません) 。IncoherentInstances

{-# LANGUAGE MultiParamTypeClasses, TypeFamilies,
  FlexibleInstances, FlexibleContexts,
  UndecidableInstances, IncoherentInstances #-}    

class Rotable a r where
    rot :: a -> r

instance (r ~ (b -> a -> c)) => Rotable (a -> b -> c) r where
    rot = flip

instance (Rotable (a -> c -> d) r', r ~ (b -> r')) => Rotable (a -> b -> c -> d) r where
    rot f b = rot (`f` b)

使用例:

*Main> rot (-) 1 2
1
*Main> :t rot foldr
rot foldr :: b -> [a] -> (a -> b -> b) -> b
*Main> :t (rot . rot) foldr
(rot . rot) foldr :: [a] -> (a -> b -> b) -> b -> b
*Main> (rot . rot) foldr [1..5] (+) 0
15
于 2013-03-15T01:38:55.570 に答える