将字符串列表应用于任意函数

时间:2014-01-26 10:53:53

标签: haskell ghc type-families

我正在尝试编写一个函数,允许您将一个字符串列表“应用”到任意函数中。这是我到目前为止所得到的:

{-# LANGUAGE MultiParamTypeClasses, FlexibleInstances, OverlappingInstances, TypeFamilies #-}

class Apply a c
  where apply :: a -> [String] -> c

instance (Read a, Apply b c) => Apply (a -> b) c
  where apply _ [] = error "not enough arguments"
        apply f (x:xs) = apply (f (read x)) xs

instance (a ~ b) => Apply a b 
  where apply f [] = f
        apply _ (_:_) = error "too many arguments"

示例:

g1 :: Int -> Bool
g1 x = x > 10

g2 :: Bool -> Int -> Int
g2 b n = if b then 10*n else n-1

test1 = apply g1 ["3"]              -- False
test2 = apply g2 ["True", "33"]     -- 330
test3 = apply g2 ["False", "0"]     -- -1
test4 = apply g2 []                 -- error "not enough arguments"
test5 = apply g2 ["True", "3", "x"] -- error "too many arguments"
test6 = apply (length :: [Int] -> Int) ["[4,5,6]"]           -- 3
test7 = apply (tail :: [Char] -> [Char]) [ "['a','b','c']" ] -- "bc"

我想写下面的内容:

wrap :: (Show b, Apply a b) => a -> ([String] -> String)
wrap f xs = show $ apply f xs

但GHC抱怨:Could not deduce (Show a0) arising from a use of 'show' ...

但是,具体定义有效:

w1 xs = show $ apply g1 xs
w2 xs = show $ apply g2 xs

并生成[String] -> String类型的函数:

test8 = w1 ["20"]          -- "True"
test9 = w2 ["False", "3" ] -- "2"

我有办法让wrap工作吗?有没有更好的方法来实现apply

2 个答案:

答案 0 :(得分:4)

您也可以尝试更改“应用于

”的声明
class Apply a c | a -> c
     where apply :: a -> [String] -> c

添加FunctionalDependencies扩展,您当前的包装签名

我认为这与“无法推断”错误后出现的重叠实例错误有关。

答案 1 :(得分:1)

如果您添加ScopedTypeVariables并写下此内容似乎有效:

wrap :: forall a b . (Show b, Apply a b) => a -> ([String] -> String)
wrap f xs = show (apply f xs :: b)

说实话,我不太确定为什么会修复它,但是你在Apply的两个重叠实例处于微妙的领域,我认为这需要说服GHC使用传入的{在Apply的类型签名中声明的{1}}实例,而不是立即使用wrap实例解析对apply的调用,然后想要a ~ b类型Show 1}}因此。