3

ネストされたリスト構造の最も内側のリストに特定の値を追加する関数を作成しようとしていますが、そのような関数の型シグネチャが何であるかさえわからない場合、型でエラーが発生します.

digpend a xs = case xs of [_:_] -> map (digpend a) xs
                          [[]]  -> [[a]]
                          xs    -> a:xs

例えば、

digpend 555 [ [ [ 5,1,-12,33 ] , [ 6,22 ] ] , [ [ -9,0,9,12,83 ] ] ]

戻るべき

[ [ [ 555,5,1,-12,33 ] , [ 555,6,22 ] ] , [ [ 555,-9,0,9,12,83 ] ] ]

そして理想的には、再帰によるネストのあらゆるレベルで機能します。これは許されますか?

4

3 に答える 3

6

以下は、型クラスを使用した完全に満足できる実装ではありません。

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances #-}

class DigPend a b where
  digpend :: a -> [b] -> [b]

instance DigPend a a where
  digpend x xs = (x:xs)

instance (DigPend a b) => (DigPend a [b]) where
  digpend x xs = map (digpend x) xs

引数の型が完全に指定されている限り、うまく機能します。

*Main> digpend (5 :: Int) ([6,7,8] :: [Int])
[5,6,7,8]
*Main> digpend (555 :: Int) ([[[5,1,-12,33],[6,22]],[[-9,0,9,12,83]]] :: [[[Int]]])
[[[555,5,1,-12,33],[555,6,22]],[[555,-9,0,9,12,83]]]
*Main> digpend (5 :: Int) ([] :: [Int])
[5]
*Main> digpend (5 :: Int) ([] :: [[Int]])
[]

ただし、 like の呼び出しは、digpend 5 [6,7,8]多くの「あいまいな型変数」エラーを引き起こします。数値リテラル like5は多相的 ( の任意のインスタンスに存在できますNum) であり、ghci通常は喜んでデフォルトで に設定されますがInteger、最初に の型クラス制約を解決しようとしますDigPend。その段階では、どのインスタンスを適用するかを知るのに十分な型情報がありませんdigpend

于 2013-06-28T16:37:51.727 に答える
4

これを解決するには、少しの型レベルのプログラミング スキルといくつかの GHC 拡張機能が必要です。

{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE OverlappingInstances #-}

class Digpend a d where
  digpend :: a -> d -> d

instance (Digpend a d) => Digpend a [d] where
  digpend a list = map (digpend a) list

instance Digpend a [a] where
  digpend a list = a : list

main = do
  -- We have to help the compiler disambiguate the numbers by putting explicit
  -- type signatures:
  print $ digpend 
    (555 :: Int) 
    ([ [ [ 5,1,-12,33 ] , [ 6,22 ] ] , [ [ -9,0,9,12,83 ] ] ] :: [[[Int]]])
  -- In case of specific literals, such as `Char`, it's not a problem though.
  print $ digpend '!' [['a', 'b', 'c'], "def"]

結果:

[[[555,5,1,-12,33],[555,6,22]],[[555,-9,0,9,12,83]]]
["!abc","!def"]
于 2013-06-28T16:34:21.197 に答える
2

独自のデータ型を定義できる/許可されている場合は、次のものも使用できます。

data Tree a = Leaves [a] | InnerNodes [Tree a] deriving (Show)

digpend :: a -> Tree a -> Tree a
digpend x (Leaves xs) = Leaves $ x:xs
digpend x (InnerNodes []) = InnerNodes [Leaves [x]]
digpend x (InnerNodes xs) = InnerNodes . map (digpend x) $ xs

出力例:

*Main> digpend 10 $ InnerNodes [ Leaves [], Leaves [], InnerNodes []]
InnerNodes [Leaves [10],Leaves [10],InnerNodes [Leaves [10]]]
*Main> digpend 555 $ InnerNodes [InnerNodes [Leaves [5, 1, -12, 33], Leaves [6, 22]], InnerNodes [Leaves [-9, 0, 9, 12, 83]]]
InnerNodes [InnerNodes [Leaves [555,5,1,-12,33],Leaves [555,6,22]],InnerNodes [Leaves [555,-9,0,9,12,83]]]
于 2013-06-28T17:27:05.880 に答える