1

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

関数を引数としてflist取り、引数がリストになるが、とまったく同じように動作する別の関数を返す関数を作成したいと思います。ff

例えば:

let f x1 x2 x3 = x1+ x2 + x3

この振る舞いが欲しい

(flist f) [x1,x2,x3] = x1+x2+x3

リストの長さが3でない場合は、何らかの方法で動作する可能性があります。flistすべての関数を処理する必要があります(3つの引数を持つ関数だけでなく、if g x1 x2 x3 x4 = x1+x2+x3*x4、then (flist g) [x1,x2,x3,x4] = x1+x2+x3*x4)。

私はこれを試しました、

flist f [] = f
flist f (x:xs) = flist (f x) xs

しかし、それは機能していません。どうすればこれを達成できますか?これを行うためにデータ型を使用できますか?

4

5 に答える 5

5

型族の場合、かなり遠くまで行くことができますが、それは確かに気の弱い人向けではありません。

{-# LANGUAGE FlexibleContexts  #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies      #-}

class FList a where
  type Point a
  flist :: a -> [Point a] -> Point a

instance FList (a -> a) where
  type Point (a -> a) = a
  flist f [x] = f x

instance (FList (a -> b), a ~ Point (a -> b)) => FList (a -> (a -> b)) where
  type Point (a -> (a -> b)) = Point (a -> b)
  flist f (x : xs) = flist (f x) xs

あなたの例では、次のようになります。

> let f x y z = x + y + z
> flist f [2, 3, 5]
10
于 2012-09-06T08:33:11.680 に答える
2

flistあなたはそれを与えるための賢明なタイプがないので、あなたはあなたを直接作成することはできません。

flist :: (a -> a -> a -> ..... -> a) -> [a] -> a

リストの長さに応じて、リストの長さがflistわかったら、つまりコンパイル時ではないので、リストをコンパイルすることはできません。

Template Haskellを使用すると、次のように使用できる「関数」を作成flistできますが[flist| (+) [3,4] ]、Template Haskellは非常に高度なものであり、今は避けるべきだと思います。構文は、必要な構文よりもさらに醜いです。(+) 3 4

引数の数がわかっている場合は、次の関数のいずれかを使用できます。

flist1 f [x] = f x
flist2 f [x,y] = f x y
flist3 f [x,y,z] = f x y z
flist4 f [a,b,c,d] = f a b c d
flist5 f [a,b,c,d,e] = f a b c d e

ただし、それらを加算するなど、それらと統一された何かを実行したい場合は、またはのような事前に作成された上位関数を使用して、を使用しsumproduct加算または乗算するか、独自の関数をロールすることができますfoldl。(たとえば、の言語定義はsumですsum = foldl (+) 0

于 2012-09-06T06:13:04.757 に答える
2

これは、固定数の引数に対してはそれほど難しくありません。

flist3 f [a,b,c] = f a b c
flist3 _ _       = 0

(数値コンテキストで関数を使用していることに気付いたので、デフォルトで0は完全に問題ありません。)

Maybeより一般的なコンテキストでは、値を返すことにより、一致の成功または失敗を表すことができます。

flist3 f [a,b,c] = Just $ f a b c
flist3 _ _       = Nothing

これは、次のように使用できます。

import Data.Maybe

exp f n = (sum . mapMaybe (flist3 f) $ booleanCube n) / 2^n

(関数をリストにmapMaybeマップしますが、sを削除し、値をリストに収集します。sを削除することが望ましい動作でない場合は、代わりに使用できます(関数にいくつかの調整を加えます)。a -> Maybe bNothingJustNothingmapM

ただし、型などの関数を受け取ることができると想定される場合、expのアリティは固定されていないため、使用可能な型シグネチャを与えることは困難です(Haskellのような非依存型言語ではおそらく不可能です) 。a -> a -> aa -> a -> a -> aexpf

(@Mysticが示すように、型クラスを使用してHaskellで可変個引数関数を作成することは可能ですが、それはあなたが望むものとはわずかに異なる振る舞いをします。)

于 2012-09-06T07:41:03.383 に答える
0
flist f [] = f
flist f (x:xs) = flist (f x) xs

fのタイプが固定されていないため、このようなものは機能しません。

f :: (? -> b) -> [a] -> b 

何に挿入しますか?リスト内の要素の数によって異なります。
型クラスのようなものを使用して、そのような関数を定義することができます。

1つの方法は、使用しているすべてのタイプの関数に対して各関数を明示的に定義することです。または、小さなタイプのハッカーを使用することもできます。

ある種のトリックを使用してそれが可能であることを示すために、私は厄介なハックを書きました。すべての引数の型を明示的に指定する必要があるため、まだあまり柔軟性がありません。いくつかの機能依存性を追加すると、それが解決する可能性があります。要素の数が関数fの順序と一致しない場合、例外が発生します。

{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}

class FList a b c where 
    flist :: a -> b -> c

instance FList a [s] a where 
    flist x _ = x


instance (FList a [s] b) => FList (s -> a) [s] b where 
    flist f (x:xs) =  flist (f x) xs


f:: Int -> Int -> Int -> Int 
f a b c = a + b * c

test :: [Int]
test = [1,2,3]

foo :: Int 
foo = (flist f) test  

あなたがやろうとしていることは、おそらくそのような種類の関数を必要としないでしょう。私の唯一のアドバイスは、コードを再検討して、単純なものが適合するかどうかを確認することです。

于 2012-09-06T07:37:11.700 に答える
0

アリティジェネリックプログラミングに関する多くの論文があります。

http://www.seas.upenn.edu/~ccasin/papers/aritygen.pdf

ただし、高度な一般的な手法は必要なく、問題を回避できる可能性があるため、手元にあるより大きなタスクについて説明する必要があります。

于 2012-09-06T08:39:09.963 に答える