在不声明实例的情况下调用类中的函数

时间:2017-06-20 09:41:24

标签: haskell

我想在Haskell中创建一个函数,它根据给定的数据类型执行不同的操作。我认为课程应该做我想要的,但现在我遇到了问题。我希望能够做的是类似于:

let x1 = myFunction :: MyInstance1
let x2 = myFunction :: MyInstance2

并且它根据给定的实例执行不同的操作。

我目前的方法是

class MyClass a where
    create :: Int -> a
    doSomething :: a -> [Int]

    myFunction :: [Int]
    myFunction = doSomething $ create 4

instance MyClass MyInstance1 where
    -- implementation of create and doSomething

instance MyClass MyInstance2 where
    -- implementation of create and doSomething

然而,编译器告诉我"类型变量a0在模糊性检查中是不明确的,因为myFunction'"从我读过的内容来看,这与编译器不知道什么是“做什么”的实例有关。打电话。

那么有没有办法打电话给'做某事'在"泛型"方式并在以后强制执行数据类型?或者我的问题需要完全不同的方法吗?

---编辑---

所以我应用了 chi 对我的问题的答案,但它还没有完全解决它。这是我的代码

{-# LANGUAGE AllowAmbiguousTypes #-}

class C a where
  myFunction :: Int
  create :: Int -> a
  doSomething :: a -> Int
  -- anotherFunction :: Int -> Int
  -- anotherFunction x = doSomething $ create 4

instance C Int where
  myFunction = 1
  create x = 2 * x
  doSomething x = x + 4

instance C Bool where
  myFunction = 2
  create x = True
  doSomething x = if x then 42 else 24

这会在提示符中编译和我

create @ Bool 4
create @ Int 4

返回预期结果。但是, anotherFunction 无法正确编译,并提供错误消息

Test.hs:8:23: error:
    • Could not deduce (C a0) arising from a use of ‘doSomething’
      from the context: C a
        bound by the class declaration for ‘C’ at Test.hs:(3,1)-(8,44)
      The type variable ‘a0’ is ambiguous
      These potential instances exist:
        instance C Bool -- Defined at Test.hs:15:10
        instance C Int -- Defined at Test.hs:10:10
    • In the expression: doSomething $ create 4
      In an equation for ‘anotherFunction’:
          anotherFunction x = doSomething $ create 4
Failed, modules loaded: none.

在此上下文中是否根本无法使用 doSomething ?我的想法是以相同的方式为所有实例实现该函数,然后编写

anotherFunction @ Bool 4
anotherFunction @ Int 6

1 个答案:

答案 0 :(得分:4)

你需要几个扩展来做到这一点,但它是可行的。这是一个GHCi会议,显示:

> :set -XAllowAmbiguousTypes
> class C a where myFunction :: Int
> instance C Int where myFunction = 1
> instance C Bool where myFunction = 2
> :set -XTypeApplications
> myFunction @ Int
1
> myFunction @ Bool
2

“旧”解决方案是添加代理参数

class C a where myFunction :: proxy a -> Int

但希望这会在几年内淡出风格 - 我发现传递类型明显比传递代理更清晰。

完整代码,另一个例子:

{-# LANGUAGE AllowAmbiguousTypes, TypeApplications, ScopedTypeVariables #-}

class C a where
  myFunction :: Int
  create :: Int -> a
  doSomething :: a -> Int
  anotherFunction :: Int -> Int
  anotherFunction x = doSomething $ create @ a 4

instance C Int where
  myFunction = 1
  create x = 2 * x
  doSomething x = x + 4

instance C Bool where
  myFunction = 2
  create x = True
  doSomething x = if x then 42 else 24

试验:

> :set -XTypeApplications
> anotherFunction @ Bool 4
42
> anotherFunction @ Int 6
12