Haskell:将积分转换为浮点(或浮点数)。混合浮子和整数

时间:2018-05-10 16:33:41

标签: haskell types

我仍然很难将我的大脑缠绕在Haskell及其类型系统上。我发布了另一个问题:Haskell Converting Int to Float 这肯定有帮助,但我仍然坚持。我认为这是一个更简单的例子:

ymod2 :: Integral b => b -> [b]
ymod2 n = map (\y->(y `mod` 2)) [0..n]    

powersOfx :: (Enum b, Floating b) =>  b -> b -> [b]
powersOfx n x = map (\y->(x**y)) [0..n]

thirdLst :: (Integral a, Enum a, Enum b, Floating b) => a -> b -> [b]    
thirdLst n x = zipWith (*) (ymod2 n) (powersOfx (fromIntegral n) x)

正如你所看到的,我有一个函数,它接受一个积分(ymod2)和一个带有Enum,Floating的函数。这些都在thirdLst中使用(通过zipWith)。我通过thirdLst积分和浮动。我确实尝试将Integral更改为浮动以在powersOfx中使用。当我把它加载到WinGHCi中时,我得到:

• Couldn't match type ‘b’ with ‘a’
  ‘b’ is a rigid type variable bound by
    the type signature for:
      thirdLst :: forall a b.
                  (Integral a, Enum a, Enum b, Floating b) =>
                  a -> b -> [b]
   // and quite a bit more which I can post if desired

我尝试了各种排列。我已经删除了fromIntegral,我尝试了不同的类型,但似乎没有任何效果。 我认为我的核心问题可能是如何转换类型。我想从整体上就可以做到。我意识到,很可能,在这个人为的例子中,powersOfx方法可以被重写以使用不同的类型。我的问题仍然存在。这就是如何在压缩它们时使这两种方法很好地协同工作。

谢谢,戴夫

更新。基于阅读Willem的回答,我能够通过将thirdLst替换为:

来使我的代码正常工作
thirdLst :: (Integral a, Floating b, Enum b) => a -> b -> [b]    
thirdLst n x = zipWith (*) (map fromIntegral (ymod2 n)) (powersOfx (fromIntegral n) x)

我相信Willem的例子远非优越,未来的读者应该研究他的答案。我将他的答案标记为正确答案。谢谢Willem!

1 个答案:

答案 0 :(得分:3)

Haskell(数字)类型系统

  

我仍然很难将我的大脑缠绕在Haskell及其类型系统上。

我认为Haskell中的数值类型有一些方面:

  1. 类型之间没有隐式转换(不是数字类型之间,也不是其他类型之间),因此您无法将Int隐式转换为Float;
  2. 大多数运算符使用相同的类型。例如(+) :: Num a => a -> a -> a,这意味着如果其中一个操作数是Int,那么另一个操作数和结果都是Int s;和
  3. 数字运算符(如(+)(-)(**))来自类型。例如,(**) :: Fractional a => a -> a -> a来自Fractional类型类。
  4. 导出函数的类型(以及它有问题的原因)

    现在让我们模拟Haskell编译器。您定义了一个函数:

    thirdLst n x = zipWith (*) (ymod2 n) (powersOfx (fromIntegral n) x)
    

    所以我们在这里看到该函数有两个参数nx,所以首先我们假设thirdLst有类型:

    thirdLst :: a -> b -> c
    

    但我们仍然需要通过查看表达式来分析类型。我们看到ymod2 :: Integral d => d -> [d](我们这里使用另一个名称,因为那些基本上是不同的变量)函数被调用,这意味着n的类型是a以及{{ 1}},这意味着da属于同一类型,d生成列表ymod2 n。我们还必须添加[a]类型,现在我们的函数类型是:

    Integral a

    我们还在表达式中看到fromIntegral :: (Integral e, Num f) => e -> fthirdLst :: Integral a => a -> b -> c ymod2 n :: Integral a => [a] 作为参数调用,因此我们得出结论na ~ ea是相同的类型),e的类型为fromIntegral n。我们再次向Num f => f添加Integral类型约束,但由于它已经受到约束,因此a上的约束保持不变:

    a

    thirdLst :: Integral a => a -> b -> c ymod2 n :: Integral a => [a] fromIntegral n :: Num f => f 表达式只是fromIntegral的子表达式,因为(powersOfx (fromIntegral n) x)的类型为powersOfx。因此,我们知道powersOfx :: (Enum g, Floating g) => g -> g -> [g]f ~ g,因此我们知道表达式的结果是b ~ g,我们必须添加[b]Enum b作为约束:

    Floating b

    到目前为止还没有问题,thirdLst :: (Integral a, Enum b, Floating b) => a -> b -> c ymod2 n :: Integral a => [a] fromIntegral n :: Num b => b powersOfx (fromIntegral n) x :: (Enum b, Floating b) => [b] thirdLstn的两个参数有不同的类型,但现在我们使用zipWith :: (h -> i -> j) -> [h] -> [i] -> [j],我们使用as第一个参数(*) :: Num k => k -> k -> k,因此我们知道x,因此我们的k ~ h ~ i ~ j具有类型:

    zipWith (*)

    现在出现了问题,我们发现zipWith (*) :: Num k => [k] -> [k] -> [k] 的两个参数需要具有相同的类型。由于zipWith (*)ymod2 n :: Integral a => [a]是我们用于powersOfx (fromIntegral n) x :: (Enum b, Floating b) => [b]的参数,因此zipWith (*)表示k ~ a ~ bka都是相同的类型。所以现在我们得出结论:

    b

    这意味着这两个参数需要具有相同的类型。现在,这已经导致一个重要问题:数字通常不会同时为thirdLst :: (Integral a, Enum a, Floating a, Num a) => a -> a -> [a] Integral。在最常见的数值库中,没有同时具有FloatingFloating的数字类型。所以这使得这个功能毫无用处。

    允许更多自由

    因此,我们需要找到更多通用函数,以及更多自由。您的Integral功能限制:由于列表的长度powersOfx需要具有相同的类型。我们可以构建一个两个类型独立的区域:

    x

    对于import Data.List(genericTake) powersOfx :: (Num a, Integral i) => i -> a -> [a] powersOfx n x = genericTake (n+1) (iterate (x*) 1) ,您基本上构建了一个长度类似于ymod2的列表。因此,我们可以使用cycle :: [a] -> [a],再使用[0, 1, 0, 1, ...]

    genericTake (n+1)

    然后我们的功能是:

    ymod2 :: (Num a, Integral i) => i -> [a]
    ymod2 n = genericTake (n+1) (cycle [0, 1])