2

私は Haskell の初心者で、次のコードを持つプロジェクトに取り組んでいます。

data Nested a = Elem a | Nested [Nested a] deriving (Eq, Show)
data Symbol a = Value a | Transformation (a -> a -> a) deriving (Show)


toSymbol :: [Char] -> Nested (Symbol Integer)
toSymbol x  
|all isDigit x = Elem (Value (strToInt x))
|x == "+" = Elem (Transformation (\x y -> x + y))

この関数の型が Nested (Symbol Integer) に制限されるのを避ける方法はありますか? Symbol を使用して多くの異なる型を表し、関数 toSymbol を次の行に沿って使用したいと思います。

toSymbol x  
|x == "1" = Elem (Value 1)
|x == "+" = Elem (Transformation (\x y -> x + y))
|x == "exampleword" = Elem (Value "word")
|x == "concatenate()" = Elem (Transformation concatTwoStrings)

このような関数の型シグネチャが何であるかはわかりません。これに似た機能を得るためにできることはありますか?

4

2 に答える 2

3

それを行うための単一の関数を書くことは不可能だと思います。考えられる解決策の 1 つは、単一関数 API を保持する型クラスを使用することです。

{-# LANGUAGE FlexibleInstances #-}

...

class Token a where
    toSymbol :: String -> Nested a

instance Token (Symbol Integer) where
    toSymbol x
        |all isDigit x = Elem (Value (read x))
        |x == "+" = Elem (Transformation (\x y -> x + y))
        |otherwise = error "Wrong type"

instance Token (Symbol String) where
    toSymbol "exampleword" = Elem (Value "word")
    toSymbol "concatenate()" = Elem (Transformation (++))
    toSymbol _ = error "Wrong type"
于 2013-10-30T06:13:44.423 に答える
3

型シグネチャを理解できない理由は、「関数の戻り値の型を、渡された文字列の値に依存させること、つまり依存型プログラミング」を行おうとしているためです。文字列の値は次のようになります。実行時にのみ使用できます。

したがって、基本的に : と言おうとすると、文字列の実行時値toSymbol :: String -> Nested (Symbol a)a依存し、コンパイラがそれについて不平を言う理由です。

すべての部分が適合するように型を調整する方法は多数あります。考えられる解決策の 1 つは、シンボルが持つことができる異なる型の値を指定する新しい型を使用することです。以下に例を示します。

data Nested a = Elem a | Nested [Nested a] deriving (Eq, Show)
data Symbol a = Value a | Transformation (a -> a -> a)
data SymbolType = SInteger Integer | SString String

addSymbols :: SymbolType -> SymbolType -> SymbolType
addSymbols (SInteger a) (SInteger b) = SInteger (a+b)
addSymbols _ _ = error "Not possible"

concatSymbols :: SymbolType -> SymbolType -> SymbolType
concatSymbols (SString a) (SString b) = SString (a++b)
concatSymbols _ _ = error "Not possible"

toSymbol :: String -> Nested (Symbol SymbolType)
toSymbol x  
  |x == "1" = Elem (Value (SInteger 1))
  |x == "+" = Elem (Transformation addSymbols)
  |x == "exampleword" = Elem (Value (SString "word"))
  |x == "concatenate()" = Elem (Transformation concatSymbols)
于 2013-10-30T06:53:12.877 に答える