我是 Haskell 的新手,我想了解一般类型的工作原理。
应该是什么"系统"获得表达类型的思维方式?
举个例子,如果我们有:
private Boolean downloadAndSaveFile(String server, int portNumber,String user, String password) throws IOException {
FTPClient ftp = null;
// path of a file which is on a web server
String remoteFile1 = "/public_html/1/c language/Unit_1_HTML_and_Forms.pdf";
// Path of my device
File downloadFile1 = new File("/storage/emulated/0/a/new.pdf");
try {
ftp = new FTPClient();
ftp.connect(server, portNumber);
ftp.login(user, password);
ftp.setFileType(FTP.BINARY_FILE_TYPE);
ftp.enterLocalPassiveMode();
System.out.println("Reached passive");
OutputStream outputStream1 = new BufferedOutputStream(new FileOutputStream(downloadFile1));
System.out.println("Stream Created");
boolean success = ftp.retrieveFile(remoteFile1, outputStream1);
System.out.println(success);
return true;
} catch(Exception e) {
System.out.println(e);
} finally {
if (ftp != null) {
ftp.logout();
ftp.disconnect();
}
}
return true;
}
我想到的方式,只是使用直觉,但它并不总是有效。
在这种情况下,我会说:
(\x y z -> x (y z))
我很确定这应该是正确的,但有时它会更难以这种方式去思考似乎不起作用。
例如,如果我们有:
(y z) :: (t -> t1) --function y takes t and return t1
x (y z) :: (t1 -> t2) --function x takes argument of type (return type of y)
(\x y z -> x (y z)) :: (t1 -> t2) -> (t -> t1) -> t -> t2 --return type is t2 (of x) with argument of type t for function y
在这种情况下,我不知道如何找到类型,因为我猜第一个(&lt;)是两个返回1. (\x -> x (<)) or
2. (.) . (.)
的元素的函数但是我在编写孔表达式时遇到了麻烦
所以问题是,使用这种练习的最佳方法是什么?
补充:我知道如何使用Bool
检查类型,问题是如何在没有它的情况下实际找到它们(了解Haskell如何工作)。
答案 0 :(得分:7)
您可以使用:t
中的ghci
轻松检查表达式的类型:
Prelude> :t (\x y z -> x (y z))
(\x y z -> x (y z)) :: (r1 -> r) -> (r2 -> r1) -> r2 -> r
Prelude> :t (\x -> x (<))
(\x -> x (<)) :: Ord a => ((a -> a -> Bool) -> r) -> r
Prelude> :t (.) . (.)
(.) . (.) :: (b -> c) -> (a -> a1 -> b) -> a -> a1 -> c
但我认为你想自己推导出类型。
首先,我们可以从查看变量开始。这些是x
,y
和z
。我们首先分配&#34;泛型类型&#34;他们,所以:
x :: a
y :: b
z :: c
现在我们查看表达式的右侧并查看(y z)
。这意味着我们呼叫&#34;以y
为参数的z
。因此,我们专注于&#34; y
到y :: c -> d
的类型。 (y z)
的类型为(y z) :: d
。现在我们看到x (y z)
。所以我们再次专注于#34; x
到[{1}}的类型。结果我们获得了:
x :: d -> e
最后lambda表达式映射x :: d -> e
y :: c -> d
z :: c
。所以这意味着我们在结果类型中查找&#34;伪代码&#34;:\x y z -> x (y z)
。或者:
type(x) -> type(y) -> type(z) -> type('x (y z)')
对于第二个表达式,我们首先必须派生\x y z -> x (y z) :: (d -> e) -> (c -> d) -> c -> e
的类型:
(<)
这是因为Prelude> :t (<)
(<) :: Ord a => a -> a -> Bool
是(<)
中使用该类型定义的地方。
现在我们知道,我们可以查看类型签名。我们将首先假设Prelude
的类型。现在我们向右看,看到我们称之为x :: b
。这意味着我们知道x (<)
的类型为x
,我们知道Ord a => (a -> a -> Bool) -> c
。然后我们再次得到一个lambda表达式,正如我们上面所看到的,我们可以解决它:
x (<) :: c
最后,对于第三个表达式,让我们先将其重写为:
(\x -> x (<)) :: Ord a => ((a -> a -> Bool) -> c) -> c
这里的第一个 (.) (.) (.)
函数最初是(.)
(没有括号),但我们将首先删除运算符语法糖。
接下来,我们将给操作员一个名字(只是为了让我们更方便地命名)。这在Haskell中是 not ,但我们现在将忽略它。我们这样做的原因是稍后引用特定.
函数的类型:
(.)
接下来,我们查找(.1) (.2) (.3)
的类型:
(.)
所以我们先分配一些类型:
Prelude> :t (.)
(.) :: (b -> c) -> (a -> b) -> a -> c
现在我们需要进一步分析这些类型。我们以(.1) :: (b -> c) -> (a -> b) -> a -> c
(.2) :: (e -> f) -> (d -> e) -> d -> f
(.3) :: (h -> i) -> (g -> h) -> g -> i
作为参数调用(.1)
,因此我们知道(.2)
((b -> c)
的第一个参数等同于(.1)
。这意味着:
(e -> f) -> (d -> e) -> d -> f
由于类型箭头是右关联,(b -> c) ~ (e -> f) -> (d -> e) -> d -> f
实际上意味着(e -> f) -> (d -> e) -> d -> f
。所以现在我们可以进行分析:
(e -> f) -> ((d -> e) -> (d -> f))
这意味着 b -> c
~ (e -> f) -> ((d -> e) -> (d -> f))
和b ~ (e -> f)
。所以我们专注于#34;我们的第一个c ~ ((d -> e) -> (d -> f))
进入
(.1) :: (b -> c) -> (a -> b) -> a -> c
现在(.1) :: ((e -> f) -> ((d -> e) -> (d -> f))) -> (a -> (e -> f)) -> a -> ((d -> e) -> (d -> f))
的类型是
(.1) (.2)
但现在我们用(.1) (.2) :: (a -> (e -> f)) -> a -> ((d -> e) -> (d -> f))
调用该函数,因此我们必须派生(.3)
的类型。因此,我们必须使用以下方式进行类型解析:
((.1) (.2)) (.3)
这意味着 a -> (e -> f)
~ (h -> i) -> ((g -> h) -> (g -> i))
,a ~ (h -> i)
和e ~ (g -> h)
。所以现在我们已经将类型解析为:
f ~ (g -> i)
最后一行只是一种语法简化。如您所见,这会映射我们从((.1) (.2)) (.3) :: a -> c
= (h -> i) -> ((d -> (g -> h)) -> (d -> (g -> i)))
= (h -> i) -> (d -> g -> h) -> d -> g -> i
派生的类型。
正如您在三个查询中看到的那样,我们获得了相同的类型(当然,类型变量的名称也不同)。
答案 1 :(得分:2)
使用GHC编译器,您可以使用类型孔_
例如:
thing :: _
thing = (\x -> (<))
的产率:
Found hole ‘_’ with type: t -> a0 -> a0 -> Bool
Where: ‘t’ is a rigid type variable bound by
the inferred type of thing :: t -> a0 -> a0 -> Bool
at src/Expat/Data/E.hs:555:1
‘a0’ is an ambiguous type variable
To use the inferred type, enable PartialTypeSignatures
In the type signature for ‘thing’: _
我有时会在where子句中使用它来隔离较大函数中的表达式,例如
myFun :: a -> b
myFun a = otherFun thing
where
thing :: _
thing = (\x -> (<))
您也可以使用孔代替术语。例如,如果我不确定其他应该是什么,我可以在_
中替换。