我想编写一个简单的递归函数来帮助我检查一些数学问题的值,但是我似乎无法添加任何有效的输入。
这是有问题的功能
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 =>
答案 0 :(得分:3)
查看推断的类型签名,您有Integral a1
和RealFrac a1
作为约束,整个函数只返回Num a
。你所说的是这个函数采用的是Integral
和RealFrac
类型,在逻辑上但在技术上可以在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
。这可以准确地告诉您定义的哪个部分是可疑的。您可以选择使用Double
或fromIntegral
将fromInteger
的结果投射到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
值,ceiling
取RealFrac
个值,并且您将ceiling
的参数传递给fun
,因此它推断fun
还必须采用RealFrac
个值。因此受到限制。
在这种情况下,最好限制Haskell在类型推断期间考虑的选项,方法是使用您认为应该具有的类型对函数进行注释 - 错误消息将变得更具体/更窄然后将会是更加本地化的问题代码;否则,类型推断将分析整个程序并考虑太多选项。
(函数本身也是错误定义的,因为其他答案指出,但这显然不会导致类型错误)