无法将值输入函数,因为无法推导出类型

时间:2016-01-06 15:08:39

标签: haskell

我想编写一个简单的递归函数来帮助我检查一些数学问题的值,但是我似乎无法添加任何有效的输入。

这是有问题的功能

fun 1 = 1
fun n = fun (ceiling n) + 3

它似乎是(Integral a1, Num a, RealFrac a1) => a1 -> a

类型

fun任意数字作为输入会产生以下错误:

Could not deduce (Integral a10) arising from a use of ‘fun’
    from the context (Num a)
      bound by the inferred type of it :: Num a => 

2 个答案:

答案 0 :(得分:3)

查看推断的类型签名,您有Integral a1RealFrac a1作为约束,整个函数只返回Num a。你所说的是这个函数采用的是IntegralRealFrac类型,在逻辑上但在技术上可以在Haskell中实现,并且返回任何数值类型。这来自您使用ceiling的{​​{1}},其类型为(Integral b, RealFrac a) => a -> b,然后您再次传递给fun。因此n必须是Integral,但由于您将ceiling n的结果传递给fun,因此它必须也是RealFrac。第二个问题是,您根本没有给编译器足够的信息来确切地知道您想要使用哪些类型。

我的第一个建议是给fun您认为应该具有的类型签名,我猜测可能是Double -> Int。如果您执行此操作,则会出现No instance for (Integral Double) arising from use of ceiling ...的类型错误,这意味着当Double没有Integral时,您会尝试将Double用作Integral出于显而易见的原因,实施ceiling。这可以准确地告诉您定义的哪个部分是可疑的。您可以选择使用DoublefromIntegralfromInteger的结果投射到1

除此之外,除非使用值3调用此函数,否则此函数将永远不会终止。它本质上只是构建了一次又一次添加namespace App\Modules\Auth\Controllers; use App\Http\Requests; use App\Http\Controllers\Controller; use Illuminate\Http\Request; class AuthController extends Controller { public function getLogin() { return view("Auth::login"); } public function postLogin(Request $request) { $credentials = [ 'email' => $request->input('login_email'), 'password' => $request->input('login_password'), ]; if (\Sentinel::authenticate($credentials)) { return redirect('core/dashboard'); } } } 的巨大垃圾,只会占用内存和CPU。

答案 1 :(得分:1)

这是因为ceiling返回Integral,并且您以递归方式调用fun,因此它推断出fun必须接受Integral值,ceilingRealFrac个值,并且您将ceiling的参数传递给fun,因此它推断fun还必须采用RealFrac个值。因此受到限制。

在这种情况下,最好限制Haskell在类型推断期间考虑的选项,方法是使用您认为应该具有的类型对函数进行注释 - 错误消息将变得更具体/更窄然后将会是更加本地化的问题代码;否则,类型推断将分析整个程序并考虑太多选项。

(函数本身也是错误定义的,因为其他答案指出,但这显然不会导致类型错误)